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

65 lines
2.3 KiB
C

// Diagnostic for the gnoExecProbe exec-into failure: distinguishes a PATH/
// access() resolution miss from a K_execve transfer-of-control failure.
// Runs in the SAME harness as gnoExecProbe (GNO_PROG2=gnoExeced deployed to
// /bin). Each marker isolates one step so we can see exactly where exec dies.
//
// Bank-2 absolute uint16 markers (DBR-independent):
// 0x025000 C0DE reached end (fallback; set only if every exec returned)
// 0x025010 E0EC gnoExeced ran -> some exec transferred control (success)
// 0x025020 F00D access("/bin/gnoexeced", F_OK) == 0 (our libc finds it)
// else EE00|errno (access failed -> which errno)
// 0x025022 EE00|errno after execv("/bin/gnoexeced") RETURNED (explicit path,
// bypasses PATH; only set if the exec failed to transfer)
// 0x025024 EE00|errno after execvp("gnoexeced") RETURNED (PATH-resolved;
// only set if that exec failed too)
#include <stdint.h>
extern int access(const char *path, int mode);
extern int execv(const char *path, char *const *argv);
extern int execvp(const char *file, char *const *argv);
extern int errno;
#define M(a) (*(volatile uint16_t *)(a))
#define BAD 0xDEAD
#define F_OK 0
int main(void) {
char *argv[2];
int r;
M(0x025000UL) = 0x0000;
M(0x025010UL) = BAD;
M(0x025020UL) = BAD;
M(0x025022UL) = BAD;
M(0x025024UL) = BAD;
argv[0] = "gnoexeced";
argv[1] = 0;
// Step 1: does our own access() see the file gsh clearly found at /bin?
errno = 0;
r = access("/bin/gnoexeced", F_OK);
if (r == 0) {
M(0x025020UL) = 0xF00D;
} else {
M(0x025020UL) = 0xEE00 | (uint16_t)(errno & 0xFF);
}
// Step 2: explicit-path execv (bypasses $PATH entirely). On success this
// never returns -- gnoExeced sets 0x025010 + 0x025000 in the same image.
errno = 0;
execv("/bin/gnoexeced", argv);
M(0x025022UL) = 0xEE00 | (uint16_t)(errno & 0xFF); // only if it returned
// Step 3: PATH-resolved execvp, as gnoExecProbe does.
errno = 0;
execvp("gnoexeced", argv);
M(0x025024UL) = 0xEE00 | (uint16_t)(errno & 0xFF); // only if it returned
// Reached only if BOTH execs failed to transfer control.
M(0x025000UL) = 0xC0DE;
for (volatile unsigned long j = 0; j < 300000UL; j++) {
}
return 0;
}