2020-06-15 14:18:57 +00:00
|
|
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
|
|
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
2020-06-15 14:18:57 +00:00
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
2020-06-15 14:18:57 +00:00
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
|
|
#include "libc/alg/alg.h"
|
2020-11-25 16:19:00 +00:00
|
|
|
#include "libc/alg/arraylist.internal.h"
|
|
|
|
#include "libc/alg/arraylist2.internal.h"
|
|
|
|
#include "libc/alg/bisectcarleft.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/assert.h"
|
|
|
|
#include "libc/bits/bits.h"
|
2021-03-01 07:42:35 +00:00
|
|
|
#include "libc/bits/safemacros.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/calls/calls.h"
|
2020-09-28 08:13:56 +00:00
|
|
|
#include "libc/calls/struct/stat.h"
|
2021-10-04 13:24:56 +00:00
|
|
|
#include "libc/dce.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/errno.h"
|
|
|
|
#include "libc/fmt/fmt.h"
|
2022-05-25 18:31:08 +00:00
|
|
|
#include "libc/intrin/kprintf.h"
|
2022-06-20 03:17:23 +00:00
|
|
|
#include "libc/intrin/pthread.h"
|
2022-06-11 19:21:42 +00:00
|
|
|
#include "libc/intrin/spinlock.h"
|
2022-06-16 16:06:09 +00:00
|
|
|
#include "libc/intrin/wait0.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/log/check.h"
|
|
|
|
#include "libc/log/log.h"
|
2021-03-01 07:42:35 +00:00
|
|
|
#include "libc/macros.internal.h"
|
2022-06-11 19:21:42 +00:00
|
|
|
#include "libc/mem/alloca.h"
|
2021-10-04 13:24:56 +00:00
|
|
|
#include "libc/mem/mem.h"
|
2020-08-25 11:23:25 +00:00
|
|
|
#include "libc/nexgen32e/crc32.h"
|
2022-06-11 19:21:42 +00:00
|
|
|
#include "libc/nexgen32e/threaded.h"
|
2020-12-27 15:02:35 +00:00
|
|
|
#include "libc/runtime/ezmap.internal.h"
|
2021-03-08 04:23:29 +00:00
|
|
|
#include "libc/runtime/gc.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/runtime/runtime.h"
|
2022-06-11 19:21:42 +00:00
|
|
|
#include "libc/runtime/stack.h"
|
|
|
|
#include "libc/runtime/sysconf.h"
|
2021-10-04 13:24:56 +00:00
|
|
|
#include "libc/stdio/append.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/stdio/stdio.h"
|
|
|
|
#include "libc/str/str.h"
|
2022-06-11 19:21:42 +00:00
|
|
|
#include "libc/sysv/consts/clone.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/sysv/consts/madv.h"
|
|
|
|
#include "libc/sysv/consts/map.h"
|
2020-09-28 08:13:56 +00:00
|
|
|
#include "libc/sysv/consts/o.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/sysv/consts/prot.h"
|
2022-06-11 19:21:42 +00:00
|
|
|
#include "libc/time/time.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/x/x.h"
|
|
|
|
#include "third_party/getopt/getopt.h"
|
2021-10-14 00:27:13 +00:00
|
|
|
#include "tool/build/lib/getargs.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
|
2020-09-28 08:13:56 +00:00
|
|
|
#define MAX_READ FRAMESIZE
|
|
|
|
|
2020-06-15 14:18:57 +00:00
|
|
|
/**
|
|
|
|
* @fileoverview Make dependency generator.
|
|
|
|
*
|
2020-09-28 08:13:56 +00:00
|
|
|
* This generates Makefile code for source -> header dependencies.
|
|
|
|
*
|
|
|
|
* Includes look like this:
|
|
|
|
*
|
|
|
|
* - #include "root/of/repository/foo.h"
|
|
|
|
* - .include "root/of/repository/foo.inc"
|
|
|
|
*
|
|
|
|
* They do not look like this:
|
|
|
|
*
|
|
|
|
* - #include "foo.h"
|
|
|
|
* - # include "foo.h"
|
|
|
|
* - #include "foo.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
*
|
2020-09-28 08:13:56 +00:00
|
|
|
* Only the first 64kb of each source file is considered.
|
2020-06-15 14:18:57 +00:00
|
|
|
*/
|
|
|
|
|
2020-12-24 07:42:56 +00:00
|
|
|
_Alignas(16) const char kIncludePrefix[] = "include \"";
|
2020-06-15 14:18:57 +00:00
|
|
|
|
2020-09-28 08:13:56 +00:00
|
|
|
const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"};
|
|
|
|
|
|
|
|
const char *const kIgnorePrefixes[] = {
|
|
|
|
#if 0
|
|
|
|
"libc/sysv/consts/", "libc/sysv/calls/", "libc/nt/kernel32/",
|
|
|
|
"libc/nt/KernelBase/", "libc/nt/advapi32/", "libc/nt/gdi32/",
|
|
|
|
"libc/nt/ntdll/", "libc/nt/user32/", "libc/nt/shell32/",
|
|
|
|
#endif
|
2020-06-15 14:18:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Strings {
|
|
|
|
size_t i, n;
|
|
|
|
char *p;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Source {
|
2021-10-04 13:24:56 +00:00
|
|
|
unsigned hash;
|
|
|
|
unsigned name;
|
|
|
|
unsigned id;
|
2020-06-15 14:18:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Edge {
|
2021-10-04 13:24:56 +00:00
|
|
|
unsigned to;
|
|
|
|
unsigned from;
|
2020-06-15 14:18:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Sources {
|
2021-10-04 13:24:56 +00:00
|
|
|
size_t i, n;
|
|
|
|
struct Source *p;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Sauce {
|
|
|
|
unsigned name;
|
|
|
|
unsigned id;
|
2020-06-15 14:18:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Edges {
|
|
|
|
size_t i, n;
|
|
|
|
struct Edge *p;
|
|
|
|
};
|
|
|
|
|
2020-09-28 08:13:56 +00:00
|
|
|
char *out;
|
2022-06-11 19:21:42 +00:00
|
|
|
char **tls;
|
|
|
|
int threads;
|
|
|
|
char **bouts;
|
|
|
|
char **stack;
|
2020-09-28 08:13:56 +00:00
|
|
|
unsigned counter;
|
2022-06-11 19:21:42 +00:00
|
|
|
struct GetArgs ga;
|
2020-09-28 08:13:56 +00:00
|
|
|
struct Edges edges;
|
2021-10-04 13:24:56 +00:00
|
|
|
struct Sauce *sauces;
|
2020-06-15 14:18:57 +00:00
|
|
|
struct Strings strings;
|
|
|
|
struct Sources sources;
|
|
|
|
const char *buildroot;
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_t galock;
|
|
|
|
pthread_mutex_t readlock;
|
|
|
|
pthread_mutex_t writelock;
|
|
|
|
pthread_mutex_t reportlock;
|
2020-06-15 14:18:57 +00:00
|
|
|
|
2020-09-28 08:13:56 +00:00
|
|
|
unsigned Hash(const void *s, size_t l) {
|
2020-06-15 14:18:57 +00:00
|
|
|
return max(1, crc32c(0, s, l));
|
|
|
|
}
|
|
|
|
|
2020-09-28 08:13:56 +00:00
|
|
|
unsigned FindFirstFromEdge(unsigned id) {
|
|
|
|
unsigned m, l, r;
|
|
|
|
l = 0;
|
|
|
|
r = edges.i;
|
|
|
|
while (l < r) {
|
|
|
|
m = (l + r) >> 1;
|
|
|
|
if (edges.p[m].from < id) {
|
|
|
|
l = m + 1;
|
|
|
|
} else {
|
|
|
|
r = m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
2020-06-15 14:18:57 +00:00
|
|
|
void Crunch(void) {
|
|
|
|
size_t i, j;
|
2021-10-04 13:24:56 +00:00
|
|
|
sauces = malloc(sizeof(*sauces) * sources.n);
|
|
|
|
for (j = i = 0; i < sources.n; ++i) {
|
|
|
|
if (sources.p[i].hash) {
|
|
|
|
sauces[j].name = sources.p[i].name;
|
|
|
|
sauces[j].id = sources.p[i].id;
|
|
|
|
j++;
|
|
|
|
}
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
2021-10-04 13:24:56 +00:00
|
|
|
free(sources.p);
|
|
|
|
sources.p = 0;
|
|
|
|
sources.i = j;
|
|
|
|
longsort((const long *)sauces, sources.i);
|
|
|
|
longsort((const long *)edges.p, edges.i);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Rehash(void) {
|
|
|
|
size_t i, j, step;
|
|
|
|
struct Sources old;
|
|
|
|
memcpy(&old, &sources, sizeof(sources));
|
|
|
|
sources.n = sources.n ? sources.n << 1 : 16;
|
|
|
|
sources.p = calloc(sources.n, sizeof(struct Source));
|
|
|
|
for (i = 0; i < old.n; ++i) {
|
|
|
|
if (!old.p[i].hash) continue;
|
|
|
|
step = 0;
|
|
|
|
do {
|
|
|
|
j = (old.p[i].hash + step * (step + 1) / 2) & (sources.n - 1);
|
|
|
|
step++;
|
|
|
|
} while (sources.p[j].hash);
|
2021-10-04 13:24:56 +00:00
|
|
|
sources.p[j] = old.p[i];
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
free(old.p);
|
|
|
|
}
|
|
|
|
|
2020-09-28 08:13:56 +00:00
|
|
|
unsigned GetSourceId(const char *name, size_t len) {
|
2020-06-15 14:18:57 +00:00
|
|
|
size_t i, step;
|
2020-09-28 08:13:56 +00:00
|
|
|
unsigned hash;
|
2020-08-25 11:23:25 +00:00
|
|
|
i = 0;
|
|
|
|
hash = Hash(name, len);
|
2020-06-15 14:18:57 +00:00
|
|
|
if (sources.n) {
|
|
|
|
step = 0;
|
|
|
|
do {
|
|
|
|
i = (hash + step * (step + 1) / 2) & (sources.n - 1);
|
|
|
|
if (sources.p[i].hash == hash &&
|
2022-06-12 16:37:17 +00:00
|
|
|
!memcmp(name, &strings.p[sources.p[i].name], len)) {
|
2020-06-15 14:18:57 +00:00
|
|
|
return sources.p[i].id;
|
|
|
|
}
|
|
|
|
step++;
|
|
|
|
} while (sources.p[i].hash);
|
|
|
|
}
|
|
|
|
if (++sources.i >= (sources.n >> 1)) {
|
|
|
|
Rehash();
|
|
|
|
step = 0;
|
|
|
|
do {
|
|
|
|
i = (hash + step * (step + 1) / 2) & (sources.n - 1);
|
|
|
|
step++;
|
|
|
|
} while (sources.p[i].hash);
|
|
|
|
}
|
|
|
|
sources.p[i].hash = hash;
|
2020-08-25 11:23:25 +00:00
|
|
|
sources.p[i].name = CONCAT(&strings.p, &strings.i, &strings.n, name, len);
|
2020-06-15 14:18:57 +00:00
|
|
|
strings.p[strings.i++] = '\0';
|
2020-09-28 08:13:56 +00:00
|
|
|
return (sources.p[i].id = counter++);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShouldSkipSource(const char *src) {
|
|
|
|
unsigned j;
|
|
|
|
for (j = 0; j < ARRAYLEN(kIgnorePrefixes); ++j) {
|
|
|
|
if (startswith(src, kIgnorePrefixes[j])) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-05 20:20:41 +00:00
|
|
|
wontreturn void OnMissingFile(const char *list, const char *src) {
|
2020-09-28 08:13:56 +00:00
|
|
|
DCHECK_EQ(ENOENT, errno, "%s", src);
|
|
|
|
/*
|
|
|
|
* This code helps GNU Make automatically fix itself when we
|
|
|
|
* delete a source file. It removes o/.../srcs.txt or
|
|
|
|
* o/.../hdrs.txt and exits nonzero. Since we use hyphen
|
|
|
|
* notation on mkdeps related rules, the build will
|
|
|
|
* automatically restart itself.
|
|
|
|
*/
|
2021-10-14 00:27:13 +00:00
|
|
|
if (list) {
|
2022-05-25 18:31:08 +00:00
|
|
|
kprintf("%s %s...\n", "Refreshing", list);
|
2021-10-14 00:27:13 +00:00
|
|
|
unlink(list);
|
|
|
|
}
|
2020-09-28 08:13:56 +00:00
|
|
|
exit(1);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
|
2022-06-11 19:21:42 +00:00
|
|
|
int LoadRelationshipsWorker(void *arg) {
|
2020-09-28 08:13:56 +00:00
|
|
|
int fd;
|
|
|
|
ssize_t rc;
|
|
|
|
bool skipme;
|
|
|
|
struct Edge edge;
|
2022-06-11 19:21:42 +00:00
|
|
|
char *buf, *freeme;
|
|
|
|
char srcbuf[PATH_MAX];
|
|
|
|
size_t i, n, inclen, size;
|
2020-09-28 08:13:56 +00:00
|
|
|
unsigned srcid, dependency;
|
|
|
|
const char *p, *pe, *src, *path, *pathend;
|
|
|
|
inclen = strlen(kIncludePrefix);
|
2022-06-11 19:21:42 +00:00
|
|
|
freeme = buf = memalign(PAGESIZE, PAGESIZE + MAX_READ + 16);
|
2020-09-28 08:13:56 +00:00
|
|
|
buf += PAGESIZE;
|
|
|
|
buf[-1] = '\n';
|
2022-06-11 19:21:42 +00:00
|
|
|
for (;;) {
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_lock(&galock);
|
2022-06-11 19:21:42 +00:00
|
|
|
if ((src = getargs_next(&ga))) strcpy(srcbuf, src);
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_unlock(&galock);
|
2022-06-11 19:21:42 +00:00
|
|
|
if (!src) break;
|
|
|
|
src = srcbuf;
|
2021-10-14 00:27:13 +00:00
|
|
|
if (ShouldSkipSource(src)) continue;
|
2022-06-11 19:21:42 +00:00
|
|
|
n = strlen(src);
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_lock(&readlock);
|
2022-06-11 19:21:42 +00:00
|
|
|
srcid = GetSourceId(src, n);
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_unlock(&readlock);
|
2022-05-25 18:31:08 +00:00
|
|
|
if ((fd = open(src, O_RDONLY)) == -1) {
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_lock(&reportlock);
|
2022-05-25 18:31:08 +00:00
|
|
|
OnMissingFile(ga.path, src);
|
|
|
|
}
|
2021-10-14 00:27:13 +00:00
|
|
|
CHECK_NE(-1, (rc = read(fd, buf, MAX_READ)));
|
|
|
|
close(fd);
|
|
|
|
size = rc;
|
|
|
|
bzero(buf + size, 16);
|
|
|
|
for (p = buf, pe = p + size; p < pe; ++p) {
|
|
|
|
p = strstr(p, kIncludePrefix);
|
|
|
|
if (!p) break;
|
|
|
|
path = p + inclen;
|
|
|
|
pathend = memchr(path, '"', pe - path);
|
|
|
|
if (pathend && (p[-1] == '#' || p[-1] == '.') && p[-2] == '\n') {
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_lock(&readlock);
|
2021-10-14 00:27:13 +00:00
|
|
|
dependency = GetSourceId(path, pathend - path);
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_unlock(&readlock);
|
2021-10-14 00:27:13 +00:00
|
|
|
edge.from = srcid;
|
|
|
|
edge.to = dependency;
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_lock(&writelock);
|
2021-10-14 00:27:13 +00:00
|
|
|
append(&edges, &edge);
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_unlock(&writelock);
|
2021-10-14 00:27:13 +00:00
|
|
|
p = pathend;
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-11 19:21:42 +00:00
|
|
|
free(freeme);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadRelationships(int argc, char *argv[]) {
|
|
|
|
int i;
|
|
|
|
getargs_init(&ga, argv + optind);
|
|
|
|
for (i = 0; i < threads; ++i) {
|
|
|
|
if (clone(LoadRelationshipsWorker, stack[i], GetStackSize(),
|
|
|
|
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
|
|
|
CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
|
|
|
|
(void *)(intptr_t)i, 0, __initialize_tls(tls[i]), 64,
|
|
|
|
(int *)(tls[i] + 0x38)) == -1) {
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_lock(&reportlock);
|
2022-06-11 19:21:42 +00:00
|
|
|
kprintf("error: clone(%d) failed %m\n", i);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < threads; ++i) {
|
2022-06-16 16:06:09 +00:00
|
|
|
_wait0((int *)(tls[i] + 0x38));
|
2022-06-11 19:21:42 +00:00
|
|
|
}
|
2021-10-14 00:27:13 +00:00
|
|
|
getargs_destroy(&ga);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GetOpts(int argc, char *argv[]) {
|
|
|
|
int opt;
|
|
|
|
while ((opt = getopt(argc, argv, "ho:r:")) != -1) {
|
|
|
|
switch (opt) {
|
|
|
|
case 'o':
|
|
|
|
out = optarg;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
buildroot = optarg;
|
|
|
|
break;
|
|
|
|
default:
|
2022-05-25 18:31:08 +00:00
|
|
|
kprintf("%s: %s [-r %s] [-o %s] [%s...]\n", "Usage", argv[0],
|
2020-06-15 14:18:57 +00:00
|
|
|
"BUILDROOT", "OUTPUT", "PATHSFILE");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
2022-05-25 18:31:08 +00:00
|
|
|
if (isempty(out)) kprintf("need -o FILE"), exit(1);
|
|
|
|
if (isempty(buildroot)) kprintf("need -r o/$(MODE)"), exit(1);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
|
2022-06-11 19:21:42 +00:00
|
|
|
const char *StripExt(char pathbuf[PATH_MAX], const char *s) {
|
|
|
|
static char *dot;
|
|
|
|
strcpy(pathbuf, s);
|
|
|
|
dot = strrchr(pathbuf, '.');
|
2020-06-15 14:18:57 +00:00
|
|
|
if (dot) *dot = '\0';
|
2022-06-11 19:21:42 +00:00
|
|
|
return pathbuf;
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsObjectSource(const char *name) {
|
2020-09-28 08:13:56 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAYLEN(kSourceExts); ++i) {
|
2020-06-15 14:18:57 +00:00
|
|
|
if (endswith(name, kSourceExts[i])) return true;
|
|
|
|
}
|
2022-05-17 18:38:35 +00:00
|
|
|
if (strstr(name, "/libcxx/")) {
|
|
|
|
return true;
|
|
|
|
}
|
2020-06-15 14:18:57 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-04 13:24:56 +00:00
|
|
|
forceinline bool Bts(uint32_t *p, size_t i) {
|
|
|
|
bool r;
|
|
|
|
uint32_t k;
|
|
|
|
k = 1u << (i & 31);
|
|
|
|
if (p[i >> 5] & k) return true;
|
|
|
|
p[i >> 5] |= k;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-09-28 08:13:56 +00:00
|
|
|
size_t GetFileSizeOrZero(const char *path) {
|
|
|
|
struct stat st;
|
|
|
|
st.st_size = 0;
|
|
|
|
stat(path, &st);
|
|
|
|
return st.st_size;
|
|
|
|
}
|
|
|
|
|
2022-06-11 19:21:42 +00:00
|
|
|
void Dive(char **bout, uint32_t *visited, unsigned id) {
|
|
|
|
int i;
|
|
|
|
for (i = FindFirstFromEdge(id); i < edges.i && edges.p[i].from == id; ++i) {
|
|
|
|
if (Bts(visited, edges.p[i].to)) continue;
|
|
|
|
appendw(bout, READ32LE(" \\\n\t"));
|
|
|
|
appends(bout, strings.p + sauces[edges.p[i].to].name);
|
|
|
|
Dive(bout, visited, edges.p[i].to);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-11 19:21:42 +00:00
|
|
|
int Diver(void *arg) {
|
|
|
|
char *bout = 0;
|
2021-10-04 13:24:56 +00:00
|
|
|
const char *path;
|
2022-06-11 19:21:42 +00:00
|
|
|
uint32_t *visited;
|
2021-10-04 13:24:56 +00:00
|
|
|
size_t i, visilen;
|
2022-06-11 19:21:42 +00:00
|
|
|
char pathbuf[PATH_MAX];
|
|
|
|
int tid = (intptr_t)arg;
|
2021-10-04 13:24:56 +00:00
|
|
|
visilen = (sources.i + sizeof(*visited) * CHAR_BIT - 1) /
|
|
|
|
(sizeof(*visited) * CHAR_BIT);
|
|
|
|
visited = malloc(visilen * sizeof(*visited));
|
2022-06-11 19:21:42 +00:00
|
|
|
for (i = tid; i < sources.i; i += threads) {
|
2021-10-04 13:24:56 +00:00
|
|
|
path = strings.p + sauces[i].name;
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!IsObjectSource(path)) continue;
|
2021-10-04 13:24:56 +00:00
|
|
|
appendw(&bout, '\n');
|
|
|
|
if (!startswith(path, "o/")) {
|
|
|
|
appends(&bout, buildroot);
|
2020-09-28 08:13:56 +00:00
|
|
|
}
|
2022-06-11 19:21:42 +00:00
|
|
|
appends(&bout, StripExt(pathbuf, path));
|
2021-10-04 13:24:56 +00:00
|
|
|
appendw(&bout, READ64LE(".o: \\\n\t"));
|
|
|
|
appends(&bout, path);
|
|
|
|
bzero(visited, visilen * sizeof(*visited));
|
|
|
|
Bts(visited, i);
|
2022-06-11 19:21:42 +00:00
|
|
|
Dive(&bout, visited, i);
|
2021-10-04 13:24:56 +00:00
|
|
|
appendw(&bout, '\n');
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
2022-06-11 19:21:42 +00:00
|
|
|
free(visited);
|
|
|
|
appendw(&bout, '\n');
|
|
|
|
bouts[tid] = bout;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Explore(void) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < threads; ++i) {
|
|
|
|
if (clone(Diver, stack[i], GetStackSize(),
|
|
|
|
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
|
|
|
CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
|
|
|
|
(void *)(intptr_t)i, 0, __initialize_tls(tls[i]), 64,
|
|
|
|
(int *)(tls[i] + 0x38)) == -1) {
|
2022-06-20 03:17:23 +00:00
|
|
|
pthread_mutex_lock(&reportlock);
|
2022-06-11 19:21:42 +00:00
|
|
|
kprintf("error: clone(%d) failed %m\n", i);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < threads; ++i) {
|
2022-06-16 16:06:09 +00:00
|
|
|
_wait0((int *)(tls[i] + 0x38));
|
2022-06-11 19:21:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
int i, fd;
|
2022-06-12 16:37:17 +00:00
|
|
|
char path[PATH_MAX];
|
2022-06-11 19:21:42 +00:00
|
|
|
if (argc == 2 && !strcmp(argv[1], "-n")) exit(0);
|
|
|
|
GetOpts(argc, argv);
|
|
|
|
threads = GetCpuCount();
|
|
|
|
tls = calloc(threads, sizeof(*tls));
|
|
|
|
stack = calloc(threads, sizeof(*stack));
|
|
|
|
bouts = calloc(threads, sizeof(*bouts));
|
|
|
|
for (i = 0; i < threads; ++i) {
|
|
|
|
if (!(tls[i] = malloc(64)) ||
|
|
|
|
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
|
|
|
MAP_STACK | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
|
|
|
|
kprintf("error: mmap(%d) failed %m\n", i);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LoadRelationships(argc, argv);
|
|
|
|
Crunch();
|
|
|
|
Explore();
|
2022-06-12 16:37:17 +00:00
|
|
|
ksnprintf(path, sizeof(path), "%s.%d", out, getpid());
|
|
|
|
CHECK_NE(-1, (fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)),
|
|
|
|
"open(%#s)", path);
|
2022-06-11 19:21:42 +00:00
|
|
|
for (i = 0; i < threads; ++i) {
|
|
|
|
CHECK_NE(-1, xwrite(fd, bouts[i], appendz(bouts[i]).i));
|
|
|
|
}
|
2021-10-04 13:24:56 +00:00
|
|
|
CHECK_NE(-1, close(fd));
|
2022-06-12 16:37:17 +00:00
|
|
|
CHECK_NE(-1, rename(path, out));
|
2022-06-11 19:21:42 +00:00
|
|
|
for (i = 0; i < threads; ++i) {
|
|
|
|
munmap(stack[i], GetStackSize());
|
|
|
|
free(bouts[i]);
|
|
|
|
free(tls[i]);
|
|
|
|
}
|
2021-10-04 13:24:56 +00:00
|
|
|
free(strings.p);
|
|
|
|
free(edges.p);
|
|
|
|
free(sauces);
|
2022-06-11 19:21:42 +00:00
|
|
|
free(stack);
|
|
|
|
free(bouts);
|
|
|
|
free(tls);
|
2020-06-15 14:18:57 +00:00
|
|
|
return 0;
|
|
|
|
}
|