diff --git a/Makefile b/Makefile index fbc7d08e7..8922ffe5e 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,7 @@ include posix/Makefile include lib/Makefile include test/Makefile include log/Makefile +include coredump/Makefile # incremental build quick-fix, WARN: assuming the sources are in c DEPS := $(patsubst %.o, %.c.d, $(OBJS)) diff --git a/coredump/Makefile b/coredump/Makefile new file mode 100644 index 000000000..8b898ddb5 --- /dev/null +++ b/coredump/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for phoenix-rtos-kernel/coredump +# +# Copyright 2025 Phoenix Systems +# Author: Jakub Klimek +# + + +ifeq ($(COREDUMP_DISABLE), 1) + CPPFLAGS += -DCOREDUMP_DISABLE +else + OBJS += $(addprefix $(PREFIX_O)coredump/, coredump.o) +endif diff --git a/coredump/coredump.c b/coredump/coredump.c new file mode 100644 index 000000000..abd41bc70 --- /dev/null +++ b/coredump/coredump.c @@ -0,0 +1,378 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Coredump server communication + * + * Copyright 2025 Phoenix Systems + * Author: Jakub Klimek + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "coredump.h" + +#include "proc/threads.h" +#include "proc/ports.h" +#include "include/coredump.h" + +struct { + spinlock_t spinlock; + thread_t *toDump; + process_t *current; + thread_t *dumperQ; + oid_t oid; +} coredump_common; + + +int coredump_enqueue(process_t *process) +{ + thread_t *thread, *ghost; + spinlock_ctx_t sc; + + /* No need to protect process.ghosts, we have the last reference to a dying process */ + thread = process->ghosts; + + /* Cleanup threads that finished before crash */ + do { + while ((process->ghosts != NULL) && (thread->kstack == NULL)) { + ghost = thread; + thread = thread->procnext; + LIST_REMOVE_EX(&process->ghosts, ghost, procnext, procprev); + vm_kfree(ghost); + } + if (process->ghosts == NULL) { + return -ENOENT; + } + thread = thread->procnext; + } while (thread != process->ghosts); + + /* Find crashing thread */ + do { + if (thread->sigpend & (1u << SIGNULL)) { + break; + } + thread = thread->procnext; + } while (thread != process->ghosts); + + if ((thread->sigpend & (1u << SIGNULL)) == 0) { + return -ENOENT; + } + + hal_spinlockSet(&coredump_common.spinlock, &sc); + LIST_ADD(&coredump_common.toDump, thread); + proc_threadWakeup(&coredump_common.dumperQ); + hal_spinlockClear(&coredump_common.spinlock, &sc); + + return EOK; +} + + +static int coredump_memEntryList(coredump_memseg_t *list, size_t n) +{ + map_entry_t *e; + size_t segCnt = 0; + size_t i = 0; + + proc_lockSet(&coredump_common.current->mapp->lock); + +#ifdef NOMMU + + e = coredump_common.current->entries; + do { + if (((e->prot & PROT_READ) != 0) && ((e->prot & PROT_WRITE) != 0)) { + segCnt++; + if (i < n) { + list[i].startAddr = e->vaddr; + list[i].endAddr = e->vaddr + e->size; + i++; + } + } + e = e->next; + } while (e != coredump_common.current->entries); + +#else + + e = lib_treeof(map_entry_t, linkage, lib_rbMinimum(coredump_common.current->mapp->tree.root)); + while (e != NULL) { + if (((e->prot & PROT_READ) != 0) && ((e->prot & PROT_WRITE) != 0)) { + segCnt++; + if (i < n) { + list[i].startAddr = e->vaddr; + list[i].endAddr = e->vaddr + e->size; + i++; + } + } + e = lib_treeof(map_entry_t, linkage, lib_rbNext(&e->linkage)); + } + +#endif + + proc_lockClear(&coredump_common.current->mapp->lock); + + return segCnt; +} + + +static void coredump_handleMemRead(msg_t *msg, msg_rid_t rid) +{ + const coredump_req_t *req = (coredump_req_t *)msg->i.data; + u32 responsePort = req->mem.responsePort; + void *startAddr = req->mem.startAddr; + size_t len = req->mem.size; + msg_t memMsg; + + if (vm_mapBelongs(coredump_common.current, req->mem.startAddr, len) != 0) { + msg->o.err = -EINVAL; + proc_respond(coredump_common.oid.port, msg, rid); + return; + } + msg->o.err = EOK; + proc_respond(coredump_common.oid.port, msg, rid); + + memMsg.type = mtWrite; + memMsg.oid.id = 0; + memMsg.oid.port = responsePort; + memMsg.i.size = len; + memMsg.i.data = startAddr; + memMsg.o.size = 0; + + proc_sendFromMap(responsePort, &memMsg, coredump_common.current->mapp); +} + + +static void coredump_handleThreadRead(msg_t *msg, msg_rid_t rid) +{ + const coredump_req_t *req = (coredump_req_t *)msg->i.data; + coredump_thread_t *threadResp; + thread_t *thread; + + threadResp = (coredump_thread_t *)msg->o.data; + thread = coredump_common.current->ghosts; + if (thread != NULL) { + do { + if (proc_getTid(thread) == req->thread.tid) { + break; + } + thread = thread->procnext; + } while (thread != coredump_common.current->ghosts); + } + + if ((thread == NULL) || (proc_getTid(thread) != req->thread.tid)) { + msg->o.err = -ENOENT; + proc_respond(coredump_common.oid.port, msg, rid); + } + threadResp->stackAddr = thread->ustack; + threadResp->tid = proc_getTid(thread); + threadResp->nextTid = proc_getTid(thread->procnext); + + /* Copy userspace context */ + if (hal_cpuSupervisorMode(thread->context) == 0) { + hal_memcpy(threadResp->context, thread->context, sizeof(cpu_context_t)); + } + else { + hal_memcpy(threadResp->context, (char *)thread->kstack + thread->kstacksz - sizeof(cpu_context_t), sizeof(cpu_context_t)); + } + + msg->o.err = EOK; + proc_respond(coredump_common.oid.port, msg, rid); +} + + +static void coredump_handleMemListRead(msg_t *msg, msg_rid_t rid) +{ + coredump_memEntryList(msg->o.data, msg->o.size / sizeof(coredump_memseg_t)); + msg->o.err = EOK; + proc_respond(coredump_common.oid.port, msg, rid); +} + + +static void coredump_handleRelocRead(msg_t *msg, msg_rid_t rid) +{ +#ifdef NOMMU + + size_t i; + process_t *process = coredump_common.current; + + coredump_reloc_t *relocs = (coredump_reloc_t *)msg->o.data; + for (i = 0; i < process->relocsz && i < msg->o.size / sizeof(coredump_reloc_t); i++) { + relocs[i].vbase = process->reloc[i].vbase; + relocs[i].pbase = process->reloc[i].pbase; + } + hal_memset((char*)msg->o.data + i * sizeof(coredump_reloc_t), 0, msg->o.size - i * sizeof(coredump_reloc_t)); + + msg->o.err = EOK; + proc_respond(coredump_common.oid.port, msg, rid); + +#else + + msg->o.err = -ENOSYS; + proc_respond(coredump_common.oid.port, msg, rid); + +#endif +} + + +static void coredump_handleRead(msg_t *msg, msg_rid_t rid) +{ + const coredump_req_t *req = (coredump_req_t *)msg->i.data; + + switch (req->type) { + case COREDUMP_REQ_MEM: + return coredump_handleMemRead(msg, rid); + + case COREDUMP_REQ_THREAD: + return coredump_handleThreadRead(msg, rid); + + case COREDUMP_REQ_MEMLIST: + return coredump_handleMemListRead(msg, rid); + + case COREDUMP_REQ_RELOC: + return coredump_handleRelocRead(msg, rid); + + default: + break; + } + msg->o.err = -EINVAL; + proc_respond(coredump_common.oid.port, msg, rid); +} + + +static int coredump_threadCnt(process_t *process) +{ + thread_t *t = process->ghosts; + int count = 0; + if (t == NULL) { + return 0; + } + do { + count++; + t = t->procnext; + } while (t != process->ghosts); + + return count; +} + + +static int coredump_isRunning(int pid) +{ + process_t *p = proc_find(pid); + if (p == NULL) { + return 0; + } + proc_put(p); + return 1; +} + + +static void coredump_dump(void) +{ + spinlock_ctx_t scp; + int srvPid; + msg_t msg; + msg_rid_t rid; + int pathlen; + char *path; + thread_t *crashed; + coredump_general_t *resp; + + hal_spinlockSet(&coredump_common.spinlock, &scp); + + while (coredump_common.toDump == NULL) { + proc_threadWait(&coredump_common.dumperQ, &coredump_common.spinlock, 0, &scp); + } + crashed = coredump_common.toDump; + coredump_common.current = crashed->process; + LIST_REMOVE(&coredump_common.toDump, crashed); + + hal_spinlockClear(&coredump_common.spinlock, &scp); + + do { + if (proc_recv(coredump_common.oid.port, &msg, &rid) != 0) { + continue; + } + if (msg.type != mtOpen) { + msg.o.err = -EINVAL; + proc_respond(coredump_common.oid.port, &msg, rid); + continue; + } + } while (msg.type != mtOpen); + + resp = (coredump_general_t *)msg.o.data; + resp->pid = process_getPid(coredump_common.current); + resp->tid = proc_getTid(crashed); + resp->signo = hal_cpuGetLastBit((crashed->process->sigpend | crashed->sigpend) & ~(1u << SIGNULL)); + resp->memSegCnt = coredump_memEntryList(NULL, 0); + resp->threadCnt = coredump_threadCnt(coredump_common.current); + resp->type = (sizeof(void *) == 8) ? COREDUMP_TYPE_64 : COREDUMP_TYPE_32; + pathlen = hal_strlen(coredump_common.current->path) + 1; + path = coredump_common.current->path; + if (pathlen > sizeof(resp->path)) { + pathlen = sizeof(resp->path); + path += pathlen - sizeof(resp->path); + } + hal_memcpy(resp->path, path, pathlen); + srvPid = msg.pid; + msg.o.err = EOK; + + proc_respond(coredump_common.oid.port, &msg, rid); + + do { + if (proc_recv(coredump_common.oid.port, &msg, &rid) != 0) { + continue; + } + if (msg.pid != srvPid) { + msg.o.err = -EBUSY; + proc_respond(coredump_common.oid.port, &msg, rid); + + if (coredump_isRunning(srvPid)) { + continue; + } + else { + break; + } + } + + switch (msg.type) { + case mtRead: + coredump_handleRead(&msg, rid); + break; + case mtClose: + msg.o.err = EOK; + proc_respond(coredump_common.oid.port, &msg, rid); + break; + default: + msg.o.err = -EINVAL; + proc_respond(coredump_common.oid.port, &msg, rid); + break; + } + } while (msg.type != mtClose); + + coredump_common.current->coredump = 0; + proc_put(coredump_common.current); + coredump_common.current = NULL; +} + + +static void coredump_msgthr(void *arg) +{ + for (;;) { + coredump_dump(); + } +} + + +void _coredump_start(void) +{ + hal_spinlockCreate(&coredump_common.spinlock, "coredump"); + coredump_common.current = NULL; + coredump_common.toDump = NULL; + coredump_common.dumperQ = NULL; + + proc_portCreate(&coredump_common.oid.port); + + proc_threadCreate(NULL, coredump_msgthr, NULL, 4, SIZE_KSTACK, NULL, 0, NULL); +} diff --git a/coredump/coredump.h b/coredump/coredump.h new file mode 100644 index 000000000..b530a2f52 --- /dev/null +++ b/coredump/coredump.h @@ -0,0 +1,27 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Coredump support + * + * Copyright 2025 Phoenix Systems + * Author: Jakub Klimek + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ +#ifndef _COREDUMP_H_ +#define _COREDUMP_H_ + +#include "proc/process.h" + + +extern int coredump_enqueue(process_t *process); + + +extern void _coredump_start(void); + + +#endif /* _COREDUMP_H_ */ diff --git a/hal/aarch64/exceptions.c b/hal/aarch64/exceptions.c index 281dfb05e..94743d087 100644 --- a/hal/aarch64/exceptions.c +++ b/hal/aarch64/exceptions.c @@ -19,6 +19,7 @@ #include "hal/console.h" #include "hal/string.h" #include "include/mman.h" +#include "proc/threads.h" /* Set to 1 to print text descriptions of exceptions for architecture extensions */ @@ -184,9 +185,8 @@ static void exceptions_defaultHandler(unsigned int n, exc_context_t *ctx) hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + proc_crash(proc_current()); + proc_threadEnd(); } diff --git a/hal/armv7a/exceptions.c b/hal/armv7a/exceptions.c index f5d5748c5..c8a4ed609 100644 --- a/hal/armv7a/exceptions.c +++ b/hal/armv7a/exceptions.c @@ -19,6 +19,7 @@ #include "hal/console.h" #include "hal/string.h" #include "include/mman.h" +#include "proc/threads.h" #define EXC_ASYNC_EXTERNAL 0x16 @@ -110,9 +111,8 @@ static void exceptions_defaultHandler(unsigned int n, exc_context_t *ctx) hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + proc_crash(proc_current()); + proc_threadEnd(); } diff --git a/hal/armv7m/exceptions.c b/hal/armv7m/exceptions.c index 67672b2d4..2bbec3bdd 100644 --- a/hal/armv7m/exceptions.c +++ b/hal/armv7m/exceptions.c @@ -20,6 +20,7 @@ #include "hal/console.h" #include "hal/string.h" #include "config.h" +#include "proc/threads.h" #define SIZE_FPUCTX (16 * sizeof(u32)) @@ -114,9 +115,10 @@ __attribute__((noreturn)) static void exceptions_fatal(unsigned int n, exc_conte hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + proc_crash(proc_current()); + proc_threadEnd(); + + __builtin_unreachable(); } diff --git a/hal/armv7r/exceptions.c b/hal/armv7r/exceptions.c index 0b6f0ced5..e6ca233da 100644 --- a/hal/armv7r/exceptions.c +++ b/hal/armv7r/exceptions.c @@ -19,6 +19,7 @@ #include "hal/console.h" #include "hal/string.h" #include "include/mman.h" +#include "proc/threads.h" #define EXC_ASYNC_EXTERNAL 0x16 @@ -112,9 +113,8 @@ static void exceptions_defaultHandler(unsigned int n, exc_context_t *ctx) hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + proc_crash(proc_current()); + proc_threadEnd(); } diff --git a/hal/armv8m/exceptions.c b/hal/armv8m/exceptions.c index ab45f0c4c..0b6868bb7 100644 --- a/hal/armv8m/exceptions.c +++ b/hal/armv8m/exceptions.c @@ -18,6 +18,7 @@ #include "hal/console.h" #include "hal/string.h" #include "config.h" +#include "proc/threads.h" #define CFSR ((volatile u32 *)0xe000ed28) #define MMFAR ((volatile u32 *)0xe000ed34) @@ -133,9 +134,8 @@ void exceptions_dispatch(unsigned int n, exc_context_t *ctx) hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + proc_crash(proc_current()); + proc_threadEnd(); } diff --git a/hal/armv8r/exceptions.c b/hal/armv8r/exceptions.c index 40d7fd84e..865242330 100644 --- a/hal/armv8r/exceptions.c +++ b/hal/armv8r/exceptions.c @@ -19,6 +19,7 @@ #include "hal/console.h" #include "hal/string.h" #include "include/mman.h" +#include "proc/threads.h" #define EXC_ASYNC_EXTERNAL 0x16 @@ -112,9 +113,8 @@ static void exceptions_defaultHandler(unsigned int n, exc_context_t *ctx) hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + proc_crash(proc_current()); + proc_threadEnd(); } diff --git a/hal/ia32/exceptions.c b/hal/ia32/exceptions.c index 373bc488f..1c242a9f3 100644 --- a/hal/ia32/exceptions.c +++ b/hal/ia32/exceptions.c @@ -23,6 +23,7 @@ #include "include/mman.h" #include "include/errno.h" +#include "proc/threads.h" /* Exception stubs */ @@ -196,11 +197,8 @@ static void exceptions_defaultHandler(unsigned int n, exc_context_t *ctx) hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } - - return; + proc_crash(proc_current()); + proc_threadEnd(); } diff --git a/hal/riscv64/exceptions.c b/hal/riscv64/exceptions.c index 0b2f9293f..3d4ffa455 100644 --- a/hal/riscv64/exceptions.c +++ b/hal/riscv64/exceptions.c @@ -18,6 +18,7 @@ #include "hal/spinlock.h" #include "hal/console.h" #include "hal/string.h" +#include "proc/threads.h" #include "include/mman.h" @@ -124,9 +125,8 @@ static void exceptions_defaultHandler(unsigned int n, exc_context_t *ctx) hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + proc_crash(proc_current()); + proc_threadEnd(); } diff --git a/hal/sparcv8leon/exceptions-nommu.c b/hal/sparcv8leon/exceptions-nommu.c index ba5c68aac..a652728ee 100644 --- a/hal/sparcv8leon/exceptions-nommu.c +++ b/hal/sparcv8leon/exceptions-nommu.c @@ -19,6 +19,7 @@ #include "hal/console.h" #include "hal/string.h" #include "include/mman.h" +#include "proc/threads.h" static const char *const hal_exceptionsType(int n) @@ -137,9 +138,8 @@ void exceptions_dispatch(unsigned int n, exc_context_t *ctx) hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + proc_crash(proc_current()); + proc_threadEnd(); } diff --git a/hal/sparcv8leon/exceptions.c b/hal/sparcv8leon/exceptions.c index 7f7d1c118..0106f30c4 100644 --- a/hal/sparcv8leon/exceptions.c +++ b/hal/sparcv8leon/exceptions.c @@ -20,6 +20,7 @@ #include "hal/string.h" #include "hal/sparcv8leon/srmmu.h" #include "include/mman.h" +#include "proc/threads.h" static struct { @@ -145,9 +146,9 @@ __attribute__((noreturn)) static void exceptions_defaultHandler(unsigned int n, hal_cpuReboot(); #endif - for (;;) { - hal_cpuHalt(); - } + + proc_crash(proc_current()); + proc_threadEnd(); __builtin_unreachable(); } diff --git a/include/coredump.h b/include/coredump.h new file mode 100644 index 000000000..153f4f462 --- /dev/null +++ b/include/coredump.h @@ -0,0 +1,77 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Coredump messages + * + * Copyright 2025 Phoenix Systems + * Author: Jakub Klimek + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _PHOENIX_COREDUMP_H_ +#define _PHOENIX_COREDUMP_H_ + + +#include "types.h" + + +typedef struct { + int tid; + int nextTid; + void *stackAddr; + char context[]; +} coredump_thread_t; + + +typedef struct { + void *startAddr; + void *endAddr; +} coredump_memseg_t; + + +typedef struct { + void *pbase; + void *vbase; +} coredump_reloc_t; + + +typedef struct { + int pid; + int tid; + int signo; + enum { + COREDUMP_TYPE_32, + COREDUMP_TYPE_64 + } type; + char path[64]; + int memSegCnt; + int threadCnt; +} coredump_general_t; + + +typedef struct { + enum { + COREDUMP_REQ_THREAD, + COREDUMP_REQ_MEMLIST, + COREDUMP_REQ_RELOC, + COREDUMP_REQ_MEM, + } type; + union { + struct { + int tid; + } thread; + struct { + void *startAddr; + size_t size; + __u32 responsePort; + } mem; + }; +} coredump_req_t; + + +#endif diff --git a/main.c b/main.c index 7567e7f10..87ce4fd42 100644 --- a/main.c +++ b/main.c @@ -16,6 +16,7 @@ #include "hal/hal.h" +#include "coredump/coredump.h" #include "usrv.h" #include "lib/lib.h" #include "vm/vm.h" @@ -47,6 +48,10 @@ void main_initthr(void *unused) _hal_start(); _usrv_start(); +#ifndef COREDUMP_DISABLE + _coredump_start(); +#endif + lib_printf("main: Starting syspage programs:"); syspage_progShow(); diff --git a/proc/msg-nommu.c b/proc/msg-nommu.c index 76047121e..cfbd5d278 100644 --- a/proc/msg-nommu.c +++ b/proc/msg-nommu.c @@ -28,7 +28,7 @@ struct { } msg_common; -int proc_send(u32 port, msg_t *msg) +int proc_sendFromMap(u32 port, msg_t *msg, vm_map_t *sourceMap) { port_t *p; int err = EOK; @@ -44,7 +44,7 @@ int proc_send(u32 port, msg_t *msg) sender = proc_current(); kmsg.msg = msg; - kmsg.src = sender->process; + kmsg.src = sourceMap; kmsg.threads = NULL; kmsg.state = msg_waiting; @@ -89,6 +89,14 @@ int proc_send(u32 port, msg_t *msg) } +int proc_send(u32 port, msg_t *msg) +{ + process_t *currentProc = proc_current()->process; + vm_map_t *sourceMap = (currentProc == NULL) ? msg_common.kmap : currentProc->mapp; + return proc_sendFromMap(port, msg, sourceMap); +} + + static void proc_msgReject(kmsg_t *kmsg, port_t *p) { spinlock_ctx_t sc; @@ -228,7 +236,7 @@ int proc_respond(u32 port, msg_t *msg, msg_rid_t rid) hal_spinlockSet(&p->spinlock, &sc); kmsg->state = msg_responded; - kmsg->src = current->process; + kmsg->src = (current->process == NULL) ? msg_common.kmap : current->process->mapp; proc_threadWakeup(&kmsg->threads); hal_spinlockClear(&p->spinlock, &sc); port_put(p, 0); diff --git a/proc/msg.c b/proc/msg.c index c38934ae2..e2756432c 100644 --- a/proc/msg.c +++ b/proc/msg.c @@ -33,13 +33,13 @@ struct { } msg_common; -static void *msg_map(int dir, kmsg_t *kmsg, void *data, size_t size, process_t *from, process_t *to) +static void *msg_map(int dir, kmsg_t *kmsg, void *data, size_t size, vm_map_t *srcmap, process_t *to) { void *w = NULL, *vaddr; u64 boffs, eoffs; unsigned int n = 0, i, attr, prot; page_t *nep = NULL, *nbp = NULL; - vm_map_t *srcmap, *dstmap; + vm_map_t *dstmap; struct _kmsg_layout_t *ml = dir ? &kmsg->o : &kmsg->i; int flags; addr_t bpa, pa, epa; @@ -75,7 +75,6 @@ static void *msg_map(int dir, kmsg_t *kmsg, void *data, size_t size, process_t * eoffs = ((ptr_t)data + size) & (SIZE_PAGE - 1); } - srcmap = (from == NULL) ? msg_common.kmap : from->mapp; dstmap = (to == NULL) ? msg_common.kmap : to->mapp; if ((srcmap == dstmap) && (pmap_belongs(&dstmap->pmap, data) != 0)) { @@ -338,7 +337,7 @@ static int msg_opack(kmsg_t *kmsg) } -int proc_send(u32 port, msg_t *msg) +int proc_sendFromMap(u32 port, msg_t *msg, vm_map_t *sourceMap) { port_t *p; int err = EOK; @@ -359,7 +358,7 @@ int proc_send(u32 port, msg_t *msg) sender = proc_current(); hal_memcpy(&kmsg.msg, msg, sizeof(msg_t)); - kmsg.src = sender->process; + kmsg.src = sourceMap; kmsg.threads = NULL; kmsg.state = msg_waiting; @@ -416,6 +415,14 @@ int proc_send(u32 port, msg_t *msg) } +int proc_send(u32 port, msg_t *msg) +{ + process_t *currentProc = proc_current()->process; + vm_map_t *sourceMap = (currentProc == NULL) ? msg_common.kmap : currentProc->mapp; + return proc_sendFromMap(port, msg, sourceMap); +} + + int proc_recv(u32 port, msg_t *msg, msg_rid_t *rid) { port_t *p; @@ -529,6 +536,7 @@ int proc_respond(u32 port, msg_t *msg, msg_rid_t rid) size_t s = 0; kmsg_t *kmsg; spinlock_ctx_t sc; + process_t *currentProc = proc_current()->process; p = proc_portGet(port); if (p == NULL) { @@ -564,7 +572,7 @@ int proc_respond(u32 port, msg_t *msg, msg_rid_t rid) hal_spinlockSet(&p->spinlock, &sc); kmsg->state = msg_responded; - kmsg->src = proc_current()->process; + kmsg->src = (currentProc == NULL) ? msg_common.kmap : currentProc->mapp; proc_threadWakeup(&kmsg->threads); hal_spinlockClear(&p->spinlock, &sc); hal_cpuReschedule(NULL, NULL); diff --git a/proc/msg.h b/proc/msg.h index 59f02cbd6..a2e7afa14 100644 --- a/proc/msg.h +++ b/proc/msg.h @@ -36,7 +36,7 @@ typedef struct _kmsg_t { idnode_t idlinkage; thread_t *threads; - process_t *src; + vm_map_t *src; volatile int state; #ifndef NOMMU @@ -62,6 +62,9 @@ typedef struct _kmsg_t { */ +extern int proc_sendFromMap(u32 port, msg_t *msg, vm_map_t *sourceMap); + + extern int proc_send(u32 port, msg_t *msg); diff --git a/proc/process.c b/proc/process.c index 0959e7b32..16678f206 100644 --- a/proc/process.c +++ b/proc/process.c @@ -18,6 +18,7 @@ #include "hal/elf.h" #include "include/errno.h" #include "include/signal.h" +#include "coredump/coredump.h" #include "vm/vm.h" #include "lib/lib.h" #include "posix/posix.h" @@ -78,7 +79,20 @@ process_t *proc_find(int pid) static void process_destroy(process_t *p) { thread_t *ghost; - vm_map_t *mapp = p->mapp, *imapp = p->imapp; + vm_map_t *mapp, *imapp; + + ghost = p->ghosts; + do { + if (ghost->execdata != NULL) { + ghost->kstack = ghost->execkstack; + proc_vforkedDied(ghost, FORKED); + } + + ghost = ghost->procnext; + } while (ghost != p->ghosts); + + mapp = p->mapp; + imapp = p->imapp; perf_kill(p); @@ -102,6 +116,9 @@ static void process_destroy(process_t *p) while ((ghost = p->ghosts) != NULL) { LIST_REMOVE_EX(&p->ghosts, ghost, procnext, procprev); + if (ghost->kstack != NULL) { + vm_kfree(ghost->kstack); + } vm_kfree(ghost); } @@ -118,6 +135,12 @@ int proc_put(process_t *p) int remaining; proc_lockSet(&process_common.lock); +#ifndef COREDUMP_DISABLE + if ((p->refs == 1) && (p->coredump != 0) && (coredump_enqueue(p) == EOK)) { + proc_lockClear(&process_common.lock); + return 1; + } +#endif remaining = --p->refs; LIB_ASSERT(remaining >= 0, "pid: %d, refcnt became negative", process_getPid(p)); if (remaining <= 0) { @@ -197,6 +220,7 @@ int proc_start(void (*initthr)(void *), void *arg, const char *path) process->ghosts = NULL; process->reaper = NULL; process->refs = 1; + process->coredump = 0; proc_lockInit(&process->lock, &proc_lockAttrDefault, "process"); @@ -275,7 +299,7 @@ void process_exception(unsigned int n, exc_context_t *ctx) if (thread->process == NULL) hal_cpuHalt(); - threads_sigpost(thread->process, thread, SIGKILL); + proc_crash(thread); /* Don't allow current thread to return to the userspace, * it will crash anyway. */ @@ -710,15 +734,7 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo #else -struct _reloc { - void *vbase; - void *pbase; - size_t size; - unsigned int misalign; -}; - - -static int process_relocate(struct _reloc *reloc, size_t relocsz, char **addr) +static int process_relocate(reloc_t *reloc, size_t relocsz, char **addr) { size_t i; @@ -745,11 +761,10 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo Elf32_Shdr *shdr, *shstrshdr; Elf32_Rela rela; unsigned prot, flags, reloffs; - int i, j, relocsz = 0, badreloc = 0, err; + int i, j, badreloc = 0, err; void *relptr; char *snameTab; ptr_t *got; - struct _reloc reloc[8]; size_t stacksz = SIZE_USTACK; hal_tls_t tlsNew; ptr_t tbssAddr = 0; @@ -765,7 +780,8 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo return err; } - hal_memset(reloc, 0, sizeof(reloc)); + process->relocsz = 0; + hal_memset(process->reloc, 0, sizeof(process->reloc)); for (i = 0, j = 0, phdr = (void *)ehdr + ehdr->e_phoff; i < ehdr->e_phnum; i++, phdr++) { if (phdr->p_type == PT_GNU_STACK && phdr->p_memsz != 0) { @@ -825,15 +841,14 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo hal_memset((char *)paddr + reloffs + phdr->p_filesz, 0, round_page(phdr->p_memsz + reloffs) - phdr->p_filesz - reloffs); } - if (j >= (sizeof(reloc) / sizeof(reloc[0]))) { + if (j >= (sizeof(process->reloc) / sizeof(process->reloc[0]))) { return -ENOMEM; } - reloc[j].vbase = (void *)phdr->p_vaddr; - reloc[j].pbase = (void *)((char *)paddr + reloffs); - reloc[j].size = phdr->p_memsz; - reloc[j].misalign = phdr->p_offset & (phdr->p_align - 1); - ++relocsz; + process->reloc[j].vbase = (void *)phdr->p_vaddr; + process->reloc[j].pbase = (void *)((char *)paddr + reloffs); + process->reloc[j].size = phdr->p_memsz; + ++process->relocsz; ++j; } @@ -854,7 +869,7 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo } got = (ptr_t *)shdr->sh_addr; - if (process_relocate(reloc, relocsz, (char **)&got) < 0) { + if (process_relocate(process->reloc, process->relocsz, (char **)&got) < 0) { return -ENOEXEC; } @@ -862,13 +877,13 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo /* This is non classic approach to .got relocation. We use .got itselft * instead of .rel section. */ for (i = 0; i < shdr->sh_size / 4; ++i) { - if (process_relocate(reloc, relocsz, (char **)&got[i]) < 0) { + if (process_relocate(process->reloc, process->relocsz, (char **)&got[i]) < 0) { return -ENOEXEC; } } *entry = (void *)(unsigned long)ehdr->e_entry; - if (process_relocate(reloc, relocsz, (char **)entry) < 0) { + if (process_relocate(process->reloc, process->relocsz, (char **)entry) < 0) { return -ENOEXEC; } @@ -893,7 +908,7 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo } relptr = (void *)rela.r_offset; - if (process_relocate(reloc, relocsz, (char **)&relptr) < 0) { + if (process_relocate(process->reloc, process->relocsz, (char **)&relptr) < 0) { return -ENOEXEC; } @@ -906,7 +921,7 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo /* NOTE: Build process on NOMMU compiles a position-dependend binary but kernel treats it as a PIE. */ /* There is no need to look at the symbol and perform calculations as it is already done by static linker. */ - if (process_relocate(reloc, relocsz, relptr) < 0) { + if (process_relocate(process->reloc, process->relocsz, relptr) < 0) { return -ENOEXEC; } } @@ -923,20 +938,20 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo if (hal_strcmp(&snameTab[shdr->sh_name], ".tdata") == 0) { tlsNew.tls_base = (ptr_t)shdr->sh_addr; tlsNew.tdata_sz += shdr->sh_size; - if (process_relocate(reloc, relocsz, (char **)&tlsNew.tls_base) < 0) { + if (process_relocate(process->reloc, process->relocsz, (char **)&tlsNew.tls_base) < 0) { return -ENOEXEC; } } else if (hal_strcmp(&snameTab[shdr->sh_name], ".tbss") == 0) { tbssAddr = (ptr_t)shdr->sh_addr; tlsNew.tbss_sz += shdr->sh_size; - if (process_relocate(reloc, relocsz, (char **)&tbssAddr) < 0) { + if (process_relocate(process->reloc, process->relocsz, (char **)&tbssAddr) < 0) { return -ENOEXEC; } } else if (hal_strcmp(&snameTab[shdr->sh_name], "armtls") == 0) { tlsNew.arm_m_tls = (ptr_t)shdr->sh_addr; - if (process_relocate(reloc, relocsz, (char **)&tlsNew.arm_m_tls) < 0) { + if (process_relocate(process->reloc, process->relocsz, (char **)&tlsNew.arm_m_tls) < 0) { return -ENOEXEC; } } diff --git a/proc/process.h b/proc/process.h index c6486f5f3..166c30b81 100644 --- a/proc/process.h +++ b/proc/process.h @@ -27,6 +27,14 @@ #define MAX_PID MAX_ID +#ifdef NOMMU +typedef struct { + void *vbase; + void *pbase; + size_t size; +} reloc_t; +#endif + typedef struct _process_t { lock_t lock; @@ -40,6 +48,11 @@ typedef struct _process_t { char **envp; idnode_t idlinkage; +#ifdef NOMMU + reloc_t reloc[8]; + int relocsz; +#endif + vm_map_t map; map_entry_t *entries; vm_map_t *mapp; @@ -47,6 +60,7 @@ typedef struct _process_t { pmap_t *pmapp; int exit; + unsigned coredump : 1; unsigned lazy : 1; unsigned lgap : 1; unsigned rgap : 1; diff --git a/proc/threads.c b/proc/threads.c index 05e7d43f4..d13bb3e84 100644 --- a/proc/threads.c +++ b/proc/threads.c @@ -484,14 +484,16 @@ static void thread_destroy(thread_t *thread) proc_lockUnlock(thread->locks); } - if (thread->execdata != NULL) { - thread->kstack = thread->execkstack; - proc_vforkedDied(thread, FORKED); - } - vm_kfree(thread->kstack); - process = thread->process; if (process != NULL) { + if (process->coredump == 0) { + if (thread->execdata != NULL) { + thread->kstack = thread->execkstack; + proc_vforkedDied(thread, FORKED); + } + vm_kfree(thread->kstack); + thread->kstack = NULL; + } hal_spinlockSet(&threads_common.spinlock, &sc); LIST_REMOVE_EX(&process->threads, thread, procnext, procprev); @@ -502,6 +504,7 @@ static void thread_destroy(thread_t *thread) proc_put(process); } else { + vm_kfree(thread->kstack); vm_kfree(thread); } } @@ -987,6 +990,7 @@ void proc_threadEnd(void) cpu = hal_cpuGetID(); t = threads_common.current[cpu]; threads_common.current[cpu] = NULL; + t->context = t->kstack + t->kstacksz - sizeof(cpu_context_t); /* keep sane context for coredump */ t->state = GHOST; LIST_ADD(&threads_common.ghosts, t); _proc_threadWakeup(&threads_common.reaper); @@ -1076,6 +1080,35 @@ void proc_kill(process_t *proc) } +static void _proc_crash(thread_t *thread) +{ + process_t *process; + if (thread == NULL) { + return; + } + process = thread->process; + if (process == NULL) { + return; + } + + /* Use unused SIGNULL bit to mark which thread caused the crash */ + thread->sigpend |= (1u << SIGNULL); + process->coredump = 1; + + _proc_kill(process); +} + + +void proc_crash(thread_t *thread) +{ + spinlock_ctx_t sc; + + hal_spinlockSet(&threads_common.spinlock, &sc); + _proc_crash(thread); + hal_spinlockClear(&threads_common.spinlock, &sc); +} + + void proc_changeMap(process_t *proc, vm_map_t *map, vm_map_t *imap, pmap_t *pmap) { spinlock_ctx_t sc; @@ -1379,9 +1412,18 @@ int proc_join(int tid, time_t timeout) } if (ghost != NULL) { - LIST_REMOVE_EX(&process->ghosts, ghost, procnext, procprev); id = proc_getTid(ghost); } + + if (ghost->kstack != NULL) { + /* kstack kept for coredumping, keep the ghost till process_destroy */ + hal_spinlockClear(&threads_common.spinlock, &sc); + return err < 0 ? err : id; + } + + if (ghost != NULL) { + LIST_REMOVE_EX(&process->ghosts, ghost, procnext, procprev); + } hal_spinlockClear(&threads_common.spinlock, &sc); if ((ghost != NULL) && (ghost->tls.tls_sz != 0)) { @@ -1471,23 +1513,30 @@ static int threads_sigmutable(int sig) static int _threads_sigdefault(process_t *process, thread_t *thread, int sig) { switch (sig) { - case SIGHUP: - case SIGINT: - case SIGQUIT: - case SIGILL: - case SIGTRAP: case SIGABRT: /* And SIGIOT */ - case SIGEMT: - case SIGFPE: case SIGBUS: + case SIGFPE: + case SIGILL: + case SIGQUIT: case SIGSEGV: case SIGSYS: + case SIGTRAP: + case SIGXCPU: + case SIGXFSZ: + process->exit = sig << 8; + if (thread != NULL) { + thread->sigpend |= (1 << sig); + } + _proc_crash(thread == NULL ? process->threads : thread); + return SIGNAL_TERMINATE; + + case SIGHUP: + case SIGINT: + case SIGEMT: case SIGPIPE: case SIGALRM: case SIGTERM: case SIGIO: - case SIGXCPU: - case SIGXFSZ: case SIGVTALRM: case SIGPROF: case SIGUSR1: @@ -1573,9 +1622,9 @@ int threads_sigpost(process_t *process, thread_t *thread, int sig) } if ((process->sigactions == NULL) || (process->sigactions[sig - 1].sa_handler == SIG_DFL)) { - _threads_sigdefault(process, thread, sig); thread->sigpend &= ~sigbit; process->sigpend &= ~sigbit; + _threads_sigdefault(process, thread, sig); } } diff --git a/proc/threads.h b/proc/threads.h index 448116ee7..4122fac41 100644 --- a/proc/threads.h +++ b/proc/threads.h @@ -142,6 +142,9 @@ extern void proc_threadDestroy(thread_t *t); extern void proc_threadsDestroy(thread_t **threads, const thread_t *except); +extern void proc_crash(thread_t *thread); + + extern int proc_waitpid(int pid, int *stat, int options);