65816-llvm-mos/demos/gnoExecProbe.c
2026-07-07 18:33:48 -05:00

81 lines
2.9 KiB
C

// exec-family regression for the GNO libc (punch-list #5 + #7).
// Exercises access() over Kstat and the exec* wrappers over K_execve.
//
// Two halves, run in order so one boot can cover both:
// 1. Negative / no-2nd-program tests (always run, fully deterministic):
// - access(".", F_OK) succeeds on the login cwd (a directory).
// - access("/nonesuch/no", F_OK) fails (-1) on a missing path.
// - execvp("nosuchprog", ...) fails (-1, errno set): buildPath's
// $PATH search finds no candidate and returns before ever reaching
// the kernel, so this validates buildCmd/buildPath/access without
// needing a second executable.
// 2. exec-into (needs GNO_PROG2=demos/gnoExeced.omf placed on /bin): the
// LAST action execvp's the tiny 2nd program "gnoexeced", which sets
// its own bank-2 marker and the reached-end word. If GNO_PROG2 is
// not supplied the exec-into fails, prog1 sets the fallback reached-
// end word, and only the half-1 checks are meaningful.
//
// Bank-2 absolute uint16 markers (DBR-independent), gnoHeapProbe convention:
// 0x025000 C0DE reached end (set by gnoExeced on success, else by prog1)
// 0x025002 0001 execvp("nosuchprog") returned -1, else DEAD
// 0x025004 0001 errno was set nonzero by the failed execvp, else DEAD
// 0x025008 0001 access(".", F_OK) == 0 (existing dir), else DEAD
// 0x02500A 0001 access("/nonesuch/no", F_OK) == -1 (missing), else DEAD
// 0x025010 E0EC gnoExeced ran (exec-into transferred control), else DEAD
#include <stdint.h>
extern int access(const char *path, int mode);
extern int execvp(const char *file, char *const *argv);
extern int errno;
#define M(a) (*(volatile uint16_t *)(a))
#define OK 0x0001
#define BAD 0xDEAD
#define F_OK 0
int main(void) {
char *nope[2];
char *prog2[2];
int r;
M(0x025000UL) = 0x0000;
M(0x025002UL) = BAD;
M(0x025004UL) = BAD;
M(0x025008UL) = BAD;
M(0x02500AUL) = BAD;
M(0x025010UL) = BAD;
// access() over Kstat: existing directory vs. missing path.
if (access(".", F_OK) == 0) {
M(0x025008UL) = OK;
}
if (access("/nonesuch/no", F_OK) == -1) {
M(0x02500AUL) = OK;
}
// Failed exec: no such program on $PATH -> -1 with errno set. (This
// fails in buildPath, before K_execve, so it is safe and deterministic.)
nope[0] = "nosuchprog";
nope[1] = 0;
errno = 0;
r = execvp("nosuchprog", nope);
if (r == -1) {
M(0x025002UL) = OK;
}
if (errno != 0) {
M(0x025004UL) = OK;
}
// exec-into the 2nd program (GNO_PROG2). On success this never returns;
// gnoExeced sets 0x025010 and the reached-end word in the same image.
prog2[0] = "gnoexeced";
prog2[1] = 0;
execvp("gnoexeced", prog2);
// Only reached if the exec-into failed (no GNO_PROG2 on /bin).
M(0x025000UL) = 0xC0DE;
for (volatile unsigned long j = 0; j < 300000UL; j++) {
}
return 0;
}