feat: add process crash popups
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
@@ -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