/* * sdk-diag.c * Probes the exact libc/kernel layers the GCC driver depends on: * access/stat on the compiler backends, a direct posix_spawn of * cc1plus, and BFD-style ar archive reads on /sdk/lib/libc.a * (armap, member header at an armap offset, nested second fopen * of the same file, member ELF magic). Prints one line per probe. */ #include #include #include #include #include #include #include #define CC1PLUS "/sdk/libexec/gcc/x86_64-montauk/14.2.0/cc1plus" #define LIBC_A_DOTS "/sdk/bin/../lib/gcc/x86_64-montauk/14.2.0/../../../libc.a" static void probe(const char *p) { struct stat st; int a = access(p, X_OK); int s = stat(p, &st); printf("%-52s access=%d stat=%d", p, a, s); if (s == 0) { printf(" mode=%o size=%ld", (unsigned)st.st_mode, (long)st.st_size); } printf("\n"); } /* Replay the sequence BFD/ld performs on an ar archive. Each step prints ok/FAIL so the first broken layer is visible directly. */ static void ar_probe(const char *path) { unsigned char buf[64]; char hdr[61]; long armap_size, member_off, member_size, i; printf("ar_probe %s\n", path); FILE *f = fopen(path, "rb"); if (f == NULL) { printf(" FAIL fopen\n"); return; } /* Global magic */ if (fread(buf, 1, 8, f) != 8) { printf(" FAIL read magic\n"); fclose(f); return; } printf(" magic %s: %.7s\n", memcmp(buf, "!\n", 8) == 0 ? "ok" : "FAIL", (char *)buf); /* Armap ("/") member header at offset 8; size at header offset 48 */ if (fseek(f, 8, SEEK_SET) != 0 || fread(hdr, 1, 60, f) != 60) { printf(" FAIL read armap header\n"); fclose(f); return; } hdr[60] = '\0'; armap_size = strtol(hdr + 48, NULL, 10); printf(" armap hdr %s: name='%.4s' size=%ld fmag=%s\n", hdr[0] == '/' ? "ok" : "FAIL", hdr, armap_size, (hdr[58] == 0x60 && hdr[59] == '\n') ? "ok" : "FAIL"); /* First armap entry: 4-byte BE count, then BE member offsets */ if (fread(buf, 1, 8, f) != 8) { printf(" FAIL read armap data\n"); fclose(f); return; } member_off = ((long)buf[4] << 24) | ((long)buf[5] << 16) | ((long)buf[6] << 8) | (long)buf[7]; printf(" armap syms=%ld first member offset=%ld\n", ((long)buf[0] << 24) | ((long)buf[1] << 16) | ((long)buf[2] << 8) | (long)buf[3], member_off); /* Member header at the armap offset, via the SAME stream */ if (fseek(f, member_off, SEEK_SET) != 0 || fread(hdr, 1, 60, f) != 60) { printf(" FAIL read member header\n"); fclose(f); return; } hdr[60] = '\0'; member_size = strtol(hdr + 48, NULL, 10); printf(" member hdr: name='%.16s' size=%ld fmag=%s\n", hdr, member_size, (hdr[58] == 0x60 && hdr[59] == '\n') ? "ok" : "FAIL"); /* Nested second fopen of the same archive (ld does this per member), ELF magic read at the member data offset while `f` stays open. */ FILE *g = fopen(path, "rb"); if (g == NULL) { printf(" FAIL nested fopen\n"); fclose(f); return; } if (fseek(g, member_off + 60, SEEK_SET) != 0 || fread(buf, 1, 16, g) != 16) { printf(" FAIL nested read\n"); fclose(g); fclose(f); return; } printf(" member ELF magic %s:", memcmp(buf, "\177ELF", 4) == 0 ? "ok" : "FAIL"); for (i = 0; i < 8; i++) printf(" %02x", buf[i]); printf("\n"); /* Whole-member read through the nested stream + checksum */ { unsigned long sum = 0; long total = 0; if (fseek(g, member_off + 60, SEEK_SET) != 0) { printf(" FAIL re-seek\n"); } while (total < member_size) { unsigned char chunk[4096]; long want = member_size - total; size_t got; if (want > (long)sizeof(chunk)) want = sizeof(chunk); got = fread(chunk, 1, (size_t)want, g); if (got == 0) break; for (i = 0; i < (long)got; i++) sum = sum * 31 + chunk[i]; total += (long)got; } printf(" member read %ld/%ld bytes %s (sum=%08lx)\n", total, member_size, total == member_size ? "ok" : "FAIL", sum); } /* Interleave: original stream must still read correctly after the nested stream was used (independent positions). */ if (fseek(f, 0, SEEK_SET) == 0 && fread(buf, 1, 8, f) == 8) { printf(" interleaved re-read %s\n", memcmp(buf, "!\n", 8) == 0 ? "ok" : "FAIL"); } else { printf(" FAIL interleaved re-read\n"); } fclose(g); fclose(f); } int main(void) { probe(CC1PLUS); probe("/sdk/libexec/gcc/x86_64-montauk/14.2.0"); probe("/sdk/libexec/gcc"); probe("/sdk/bin/as.elf"); probe("/tmp"); probe("/sdk/lib/libc.a"); probe(LIBC_A_DOTS); ar_probe("/sdk/lib/libc.a"); ar_probe(LIBC_A_DOTS); pid_t pid = -1; char *argv[] = { (char *)"cc1plus", (char *)"--version", 0 }; int r = posix_spawn(&pid, CC1PLUS, 0, 0, argv, 0); printf("posix_spawn(cc1plus --version) = %d pid=%d\n", r, (int)pid); if (r == 0) { int st = -1; waitpid(pid, &st, 0); printf("cc1plus wait status = %d (exit %d)\n", st, (st >> 8) & 0xFF); } return 0; }