139 lines
5.1 KiB
C
139 lines
5.1 KiB
C
/*
|
|
* 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <spawn.h>
|
|
#include <sys/wait.h>
|
|
|
|
#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, "!<arch>\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, "!<arch>\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;
|
|
}
|