diff --git a/apps/system_monitor.cpp b/apps/system_monitor.cpp index 563bdd3..5440e87 100644 --- a/apps/system_monitor.cpp +++ b/apps/system_monitor.cpp @@ -321,9 +321,7 @@ void UpdateDisplay(Instance *instance, int index) { } int ListViewProcessesCallback(EsElement *element, EsMessage *message) { - if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED) { - message->selectItem.isSelected = processes[message->selectItem.index].data.pid == selectedPID; - } else if (message->type == ES_MSG_LIST_VIEW_SELECT && message->selectItem.isSelected) { + if (message->type == ES_MSG_LIST_VIEW_SELECT && message->selectItem.isSelected) { selectedPID = processes[message->selectItem.index].data.pid; EsCommandSetDisabled(&element->instance->commandTerminateProcess, selectedPID < 0 || !FindProcessByPID(processes, selectedPID)); } else { @@ -353,6 +351,8 @@ void TerminateProcess(Instance *instance, EsElement *, EsCommand *) { return; } + // TODO What should happen if the user tries to terminate the desktop process? + EsHandle handle = EsProcessOpen(selectedPID); if (handle) { diff --git a/apps/test.cpp b/apps/test.cpp index 51a2539..6f0e277 100644 --- a/apps/test.cpp +++ b/apps/test.cpp @@ -167,6 +167,14 @@ void InitialiseInstance(EsInstance *instance) { EsPanel *panel = EsPanelCreate(instance->window, ES_CELL_FILL, &stylePanel); + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Crash (memory error)"), [] (EsInstance *, EsElement *, EsCommand *) { + EsMemoryZero((void *) 0, 1); + }); + + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Crash (system call error)"), [] (EsInstance *, EsElement *, EsCommand *) { + EsEventSet(1); + }); + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Timing"), [] (EsInstance *, EsElement *element, EsCommand *) { EsDateComponents start, end; diff --git a/arch/x86_64/kernel.cpp b/arch/x86_64/kernel.cpp index 3470f58..6b6557e 100644 --- a/arch/x86_64/kernel.cpp +++ b/arch/x86_64/kernel.cpp @@ -459,6 +459,16 @@ extern "C" void InterruptHandler(InterruptContext *context) { currentThread->process->cExecutableName, context->rip, context->rsp, context->errorCode, context->cr2); +#ifdef PAUSE_ON_USERLAND_CRASH + if (context->rip) { + currentThread->process->pausedFromCrash = true; + // x86_64 for "jmp $". + ((uint8_t *) context->rip)[0] = 0xEB; + ((uint8_t *) context->rip)[1] = 0xFE; + goto resolved; + } +#endif + EsPrint("Attempting to make a stack trace...\n"); { diff --git a/desktop/api.cpp b/desktop/api.cpp index 34f5de7..c73af72 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -260,6 +260,16 @@ const void *const apiTable[] = { #include }; +#ifdef PAUSE_ON_USERLAND_CRASH +ES_EXTERN_C uintptr_t APISyscallCheckForCrash(uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, uintptr_t unused, uintptr_t argument3, uintptr_t argument4) { + uintptr_t returnValue = _APISyscall(argument0, argument1, argument2, unused, argument3, argument4); + EsProcessState state; + _APISyscall(ES_SYSCALL_PROCESS_GET_STATE, ES_CURRENT_PROCESS, (uintptr_t) &state, 0, 0, 0); + while (state.flags & ES_PROCESS_STATE_PAUSED_FROM_CRASH); + return returnValue; +} +#endif + MountPoint *NodeAddMountPoint(const char *prefix, size_t prefixBytes, EsHandle base, bool queryInformation) { MountPoint mountPoint = {}; EsAssert(prefixBytes < sizeof(mountPoint.prefix)); diff --git a/desktop/list_view.cpp b/desktop/list_view.cpp index 474f322..d9f434b 100644 --- a/desktop/list_view.cpp +++ b/desktop/list_view.cpp @@ -963,7 +963,13 @@ struct EsListView : EsElement { } m.type = ES_MSG_LIST_VIEW_SELECT; - fixedItemSelection = m.selectItem.index; + + if (flags & ES_LIST_VIEW_FIXED_ITEMS) { + fixedItemSelection = m.selectItem.index; + EsAssert((uintptr_t) m.selectItem.index < fixedItems.Length()); + m.selectItem.index = fixedItemIndices[m.selectItem.index]; + } + EsMessageSend(this, &m); ignore:; diff --git a/desktop/os.header b/desktop/os.header index 957a444..f0d4b0d 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -273,10 +273,11 @@ define ES_SCANCODE_WWW_STOP (0x10F) define ES_SCANCODE_WWW_REFRESH (0x110) define ES_SCANCODE_WWW_STARRED (0x111) -define ES_PROCESS_STATE_ALL_THREADS_TERMINATED (1) -define ES_PROCESS_STATE_TERMINATING (2) -define ES_PROCESS_STATE_CRASHED (4) -define ES_PROCESS_STATE_PINGED (8) +define ES_PROCESS_STATE_ALL_THREADS_TERMINATED (1 << 0) +define ES_PROCESS_STATE_TERMINATING (1 << 1) +define ES_PROCESS_STATE_CRASHED (1 << 2) +private define ES_PROCESS_STATE_PINGED (1 << 3) +private define ES_PROCESS_STATE_PAUSED_FROM_CRASH (1 << 4) define ES_FLAGS_DEFAULT (0) define ES_SUCCESS (-1) diff --git a/desktop/prefix.h b/desktop/prefix.h index 88765f8..de9f6a0 100644 --- a/desktop/prefix.h +++ b/desktop/prefix.h @@ -169,8 +169,14 @@ struct ES_INSTANCE_TYPE; #ifndef KERNEL #ifdef ES_API ES_EXTERN_C uintptr_t _APISyscall(uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, uintptr_t unused, uintptr_t argument3, uintptr_t argument4); +#ifdef PAUSE_ON_USERLAND_CRASH +ES_EXTERN_C uintptr_t APISyscallCheckForCrash(uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, uintptr_t unused, uintptr_t argument3, uintptr_t argument4); +#define EsSyscall(a, b, c, d, e) APISyscallCheckForCrash((a), (b), (c), 0, (d), (e)) +#define _EsSyscall APISyscallCheckForCrash +#else #define EsSyscall(a, b, c, d, e) _APISyscall((a), (b), (c), 0, (d), (e)) #define _EsSyscall _APISyscall +#endif #else #define EsSyscall(a, b, c, d, e) _EsSyscall((a), (b), (c), 0, (d), (e)) #endif diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp index a5cce61..4bc8e02 100644 --- a/kernel/scheduler.cpp +++ b/kernel/scheduler.cpp @@ -169,6 +169,11 @@ struct Process { KMutex crashMutex; EsCrashReason crashReason; bool crashed; +#ifdef PAUSE_ON_USERLAND_CRASH + // To allow for better remote debugging if PAUSE_ON_USERLAND_CRASH is defined, + // when a process crashes it will return to where the crash occurred and enter an infinite loop. + bool pausedFromCrash; +#endif // Termination: bool allThreadsTerminated; diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 2a5cf0d..33ffe84 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -1220,6 +1220,9 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_GET_STATE) { state.flags = (process->allThreadsTerminated ? ES_PROCESS_STATE_ALL_THREADS_TERMINATED : 0) | (process->preventNewThreads ? ES_PROCESS_STATE_TERMINATING : 0) | (process->crashed ? ES_PROCESS_STATE_CRASHED : 0) +#ifdef PAUSE_ON_USERLAND_CRASH + | (process->pausedFromCrash ? ES_PROCESS_STATE_PAUSED_FROM_CRASH : 0) +#endif | (process->messageQueue.pinged ? ES_PROCESS_STATE_PINGED : 0); SYSCALL_WRITE(argument1, &state, sizeof(EsProcessState)); @@ -1781,7 +1784,11 @@ uintptr_t DoSyscall(EsSyscallType index, uintptr_t argument0, uintptr_t argument reason.duringSystemCall = index; KernelLog(LOG_ERROR, "Syscall", "syscall failure", "Process crashed during system call [%x, %x, %x, %x, %x]\n", index, argument0, argument1, argument2, argument3); +#ifdef PAUSE_ON_USERLAND_CRASH + currentProcess->pausedFromCrash = true; +#else ProcessCrash(currentProcess, &reason); +#endif } } diff --git a/util/build_common.h b/util/build_common.h index d986e1a..01bd69e 100644 --- a/util/build_common.h +++ b/util/build_common.h @@ -295,6 +295,7 @@ Option options[] = { { "Flag.COM_OUTPUT", OPTION_TYPE_BOOL, { .b = true } }, { "Flag.POST_PANIC_DEBUGGING", OPTION_TYPE_BOOL, { .b = false } }, { "Flag.START_DEBUG_OUTPUT", OPTION_TYPE_BOOL, { .b = false } }, + { "Flag.PAUSE_ON_USERLAND_CRASH", OPTION_TYPE_BOOL, { .b = false } }, { "Dependency.ACPICA", OPTION_TYPE_BOOL, { .b = true } }, { "Dependency.stb_image", OPTION_TYPE_BOOL, { .b = true } }, { "Dependency.stb_image_write", OPTION_TYPE_BOOL, { .b = true } },