mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 06:48:31 +00:00
Initial import
This commit is contained in:
commit
c91b3c5006
14915 changed files with 590219 additions and 0 deletions
82
tool/build/build.mk
Normal file
82
tool/build/build.mk
Normal file
|
@ -0,0 +1,82 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_BUILD
|
||||
|
||||
TOOL_BUILD_FILES := $(wildcard tool/build/*)
|
||||
TOOL_BUILD_SRCS = $(filter %.c,$(TOOL_BUILD_FILES))
|
||||
TOOL_BUILD_HDRS = $(filter %.h,$(TOOL_BUILD_FILES))
|
||||
TOOL_BUILD_COMS = $(TOOL_BUILD_OBJS:%.o=%.com)
|
||||
TOOL_BUILD_BINS = $(TOOL_BUILD_COMS) $(TOOL_BUILD_COMS:%=%.dbg)
|
||||
|
||||
TOOL_BUILD_OBJS = \
|
||||
$(TOOL_BUILD_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(TOOL_BUILD_SRCS:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_BUILD_LINK = \
|
||||
$(TOOL_BUILD_DEPS) \
|
||||
o/$(MODE)/tool/build/%.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
|
||||
TOOL_BUILD_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
DSP_SCALE \
|
||||
LIBC_ALG \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_CONV \
|
||||
LIBC_DNS \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_RAND \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_TIME \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
TOOL_BUILD_LIB \
|
||||
THIRD_PARTY_DTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_STB
|
||||
|
||||
TOOL_BUILD_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_BUILD_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/tool/build/build.pkg: \
|
||||
$(TOOL_BUILD_OBJS) \
|
||||
$(foreach x,$(TOOL_BUILD_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/tool/build/%.com.dbg: \
|
||||
$(TOOL_BUILD_DEPS) \
|
||||
o/$(MODE)/tool/build/build.pkg \
|
||||
o/$(MODE)/tool/build/%.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
-@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/mkdeps.o: tool/build/mkdeps.c
|
||||
-@ACTION=OBJECTIFY.c build/compile $(OBJECTIFY.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/tool/build/generatematrix.o \
|
||||
o/$(MODE)/tool/build/mkdeps.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-O2
|
||||
|
||||
.PHONY: o/$(MODE)/tool/build
|
||||
o/$(MODE)/tool/build: \
|
||||
o/$(MODE)/tool/build/lib \
|
||||
$(TOOL_BUILD_BINS) \
|
||||
$(TOOL_BUILD_CHECKS)
|
230
tool/build/coefficients.c
Normal file
230
tool/build/coefficients.c
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/half.h"
|
||||
#include "dsp/core/q.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/dtoa/dtoa.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define USAGE \
|
||||
" [FLAGS] [INT|FLOAT...]\n\
|
||||
\n\
|
||||
Example:\n\
|
||||
\n\
|
||||
coefficients -n -- 1 4 6 4 1 # Gaussian Blur\n\
|
||||
coefficients -L16 -H235 -- .299 .587 .114 # BT.601 RGB→Y\n\
|
||||
\n\
|
||||
Flags:\n\
|
||||
-v verbose\n\
|
||||
-n normalize\n\
|
||||
-m FLEX explicit Q(bits)\n\
|
||||
-L FLEX low data value [default 0]\n\
|
||||
-H FLEX high data value [default 255]\n\
|
||||
-? shows this information\n\
|
||||
\n"
|
||||
|
||||
static struct Flags {
|
||||
bool n;
|
||||
long L, H, m;
|
||||
} flags_ = {
|
||||
.L = 0,
|
||||
.H = 255,
|
||||
};
|
||||
|
||||
static noreturn void PrintUsage(int rc, FILE *f) {
|
||||
fprintf(f, "Usage: %s%s", program_invocation_name, USAGE);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?nvrL:H:m:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
g_loglevel++;
|
||||
break;
|
||||
case 'n':
|
||||
flags_.n = true;
|
||||
break;
|
||||
case 'L':
|
||||
flags_.L = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'H':
|
||||
flags_.H = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'm':
|
||||
flags_.m = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *Normalize(int n, double A[static 8]) {
|
||||
int i;
|
||||
double sum, rnorm;
|
||||
for (sum = i = 0; i < n; ++i) {
|
||||
sum += A[i];
|
||||
}
|
||||
if (fabs(sum - 1) > DBL_MIN * n) {
|
||||
rnorm = 1 / sum;
|
||||
for (i = 0; i < n; ++i) {
|
||||
A[i] *= rnorm;
|
||||
}
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
static void GetLimits(int n, const long I[static 8], long m, long L, long H,
|
||||
long res[2][2]) {
|
||||
int i, j[8];
|
||||
long x, p[2] = {L, H};
|
||||
DCHECK(0 < n && n <= 8);
|
||||
memset(res, 0, sizeof(long) * 2 * 2);
|
||||
for (j[0] = 0; j[0] < ARRAYLEN(p); ++j[0]) {
|
||||
for (j[1] = 0; j[1] < ARRAYLEN(p); ++j[1]) {
|
||||
for (j[2] = 0; j[2] < ARRAYLEN(p); ++j[2]) {
|
||||
for (j[3] = 0; j[3] < ARRAYLEN(p); ++j[3]) {
|
||||
for (j[4] = 0; j[4] < ARRAYLEN(p); ++j[4]) {
|
||||
for (j[5] = 0; j[5] < ARRAYLEN(p); ++j[5]) {
|
||||
for (j[6] = 0; j[6] < ARRAYLEN(p); ++j[6]) {
|
||||
for (j[7] = 0; j[7] < ARRAYLEN(p); ++j[7]) {
|
||||
x = 0;
|
||||
for (i = 0; i < ARRAYLEN(j); ++i) {
|
||||
x += p[j[i]] * I[i];
|
||||
if (x < res[0][0]) res[0][0] = x;
|
||||
if (x > res[0][1]) res[0][1] = x;
|
||||
}
|
||||
x += 1l << (m - 1);
|
||||
if (x < res[0][0]) res[0][0] = x;
|
||||
if (x > res[0][1]) res[0][1] = x;
|
||||
x >>= m;
|
||||
if (x < res[1][0]) res[1][0] = x;
|
||||
if (x > res[1][1]) res[1][1] = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *GetFittingMachineWord(long L, long H) {
|
||||
if (-128 <= L && H <= 127) return "int8";
|
||||
if (0 <= L && H <= 255) return "uint8";
|
||||
if (-0x8000 <= L && H <= 0x7fff) return "int16";
|
||||
if (~0x7fffffff <= L && H <= 0x7fffffff) return "int32";
|
||||
if (0 <= L && H <= 0xffffffff) return "uint32";
|
||||
return "INT64";
|
||||
}
|
||||
|
||||
static char *DescribeMachineWord(long L, long H) {
|
||||
return xasprintf("%s[%,ld..%,ld]", GetFittingMachineWord(L, H), L, H);
|
||||
}
|
||||
|
||||
static void ShowBetterCoefficients(int n, double C[static 8], long L, long H) {
|
||||
long err, I[8], lim[2][2];
|
||||
char buf[32], kAlphabet[] = "abcdefgh";
|
||||
int i, j, m, emitted, count, indices[8];
|
||||
CHECK_LT(L, H);
|
||||
DCHECK(0 < n && n <= 8);
|
||||
for (m = 2; m < 40; ++m) {
|
||||
memset(I, 0, sizeof(I));
|
||||
if (C[6] || C[7]) {
|
||||
err = GetIntegerCoefficients8(I, C, m, L, H);
|
||||
} else {
|
||||
err = GetIntegerCoefficients(I, C, m, L, H);
|
||||
}
|
||||
GetLimits(n, I, m, L, H, lim);
|
||||
for (count = i = 0; i < n; ++i) {
|
||||
if (I[i]) {
|
||||
indices[count++] = i;
|
||||
}
|
||||
}
|
||||
if (count) {
|
||||
emitted = 0;
|
||||
if (m) emitted += printf("(");
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (i) emitted += printf(" + ");
|
||||
if (I[indices[i]] != 1) {
|
||||
emitted += printf("%ld*%c", I[indices[i]], kAlphabet[indices[i]]);
|
||||
} else {
|
||||
emitted += printf("%c", kAlphabet[indices[i]]);
|
||||
}
|
||||
}
|
||||
if (m) {
|
||||
if (m > 1) {
|
||||
emitted += printf(" + %ld", 1l << (m - 1));
|
||||
}
|
||||
emitted += printf(")>>%d", m);
|
||||
}
|
||||
printf("%*s", MAX(0, 80 - emitted), " ");
|
||||
printf("/* %s %s %s ε=%,ld */\n", gc(DescribeMachineWord(L, H)),
|
||||
gc(DescribeMachineWord(lim[0][0], lim[0][1])),
|
||||
gc(DescribeMachineWord(lim[1][0], lim[1][1])), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ReadIdealCoefficients(double C[static 8], int sn, char *S[sn]) {
|
||||
int i, n;
|
||||
if ((n = MIN(8, sn)) > 0) {
|
||||
C[0] = C[1] = C[2] = C[3] = C[4] = C[5] = 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
C[i] = strtod(S[i], NULL);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int ToolBuildCoefficients(int argc, char *argv[]) {
|
||||
int n;
|
||||
double C[8];
|
||||
GetOpts(argc, argv);
|
||||
setvbuf(stdout, malloc(PAGESIZE), _IOLBF, PAGESIZE);
|
||||
if ((n = ReadIdealCoefficients(C, argc - optind, argv + optind))) {
|
||||
if (flags_.n) Normalize(n, C);
|
||||
ShowBetterCoefficients(n, C, flags_.L, flags_.H);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
g_loglevel = kLogWarn;
|
||||
showcrashreports();
|
||||
return ToolBuildCoefficients(argc, argv);
|
||||
}
|
267
tool/build/img2code.c
Normal file
267
tool/build/img2code.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/scale/scale.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/fmt/bing.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "third_party/dtoa/dtoa.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/stb/stb_image.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
|
||||
#define USAGE \
|
||||
" [FLAGS] [PATH]\n\
|
||||
\n\
|
||||
Example:\n\
|
||||
\n\
|
||||
img2code -cw79 -p2 foo.png\n\
|
||||
\n\
|
||||
Flags:\n\
|
||||
-c compress range\n\
|
||||
-o PATH out\n\
|
||||
-r FLEX ratio\n\
|
||||
-w FLEX new width\n\
|
||||
-h FLEX new height\n\
|
||||
-p FLEX pixel y ratio\n\
|
||||
-? shows this information\n\
|
||||
\n"
|
||||
|
||||
static struct Flags {
|
||||
const char *o;
|
||||
double r, p;
|
||||
int w, h;
|
||||
bool c;
|
||||
} flags_ = {
|
||||
.o = "-",
|
||||
.p = 1,
|
||||
};
|
||||
|
||||
static noreturn void PrintUsage(int rc, FILE *f) {
|
||||
fprintf(f, "Usage: %s%s", program_invocation_name, USAGE);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
static void GetOpts(int *argc, char *argv[]) {
|
||||
int opt;
|
||||
if (*argc == 2 &&
|
||||
(strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-help") == 0)) {
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
}
|
||||
while ((opt = getopt(*argc, argv, "?co:r:w:h:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
flags_.c = true;
|
||||
break;
|
||||
case 'o':
|
||||
flags_.o = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
flags_.r = strtod(optarg, NULL);
|
||||
break;
|
||||
case 'p':
|
||||
flags_.p = strtod(optarg, NULL);
|
||||
break;
|
||||
case 'w':
|
||||
flags_.w = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
flags_.h = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
if (optind == *argc) {
|
||||
argv[(*argc)++] = "-";
|
||||
}
|
||||
}
|
||||
|
||||
static void GetOutputGeometry(long syn, long sxn, long *out_dyn, long *out_dxn,
|
||||
double *out_ry, double *out_rx) {
|
||||
double ry, rx;
|
||||
long dyn, dxn;
|
||||
if (!flags_.h && !flags_.w) {
|
||||
if (flags_.r) {
|
||||
ry = flags_.r * flags_.p;
|
||||
rx = flags_.r;
|
||||
} else {
|
||||
ry = flags_.p;
|
||||
rx = 1;
|
||||
}
|
||||
dyn = round(syn / ry);
|
||||
dxn = round(sxn / rx);
|
||||
} else if (flags_.w && !flags_.h) {
|
||||
if (flags_.r) {
|
||||
rx = 1. * sxn / flags_.w;
|
||||
ry = flags_.r * flags_.p;
|
||||
dxn = flags_.w;
|
||||
dyn = round(syn / ry);
|
||||
} else {
|
||||
rx = 1. * sxn / flags_.w;
|
||||
ry = flags_.p * rx;
|
||||
dxn = flags_.w;
|
||||
dyn = round(syn / ry);
|
||||
}
|
||||
} else if (flags_.h && !flags_.w) {
|
||||
if (flags_.r) {
|
||||
rx = flags_.r;
|
||||
ry = flags_.p * syn / flags_.h;
|
||||
dxn = flags_.w;
|
||||
dyn = round(syn / ry);
|
||||
} else {
|
||||
ry = flags_.p * syn / flags_.h;
|
||||
rx = ry;
|
||||
dyn = flags_.h;
|
||||
dxn = round(syn / rx);
|
||||
}
|
||||
} else {
|
||||
ry = flags_.p;
|
||||
rx = 1;
|
||||
dyn = round(flags_.h / ry);
|
||||
dxn = flags_.w;
|
||||
}
|
||||
*out_dyn = dyn;
|
||||
*out_dxn = dxn;
|
||||
*out_ry = ry;
|
||||
*out_rx = rx;
|
||||
}
|
||||
|
||||
static void *Deinterlace(long dcn, long dyn, long dxn,
|
||||
unsigned char dst[dcn][dyn][dxn], long syw, long sxw,
|
||||
long scw, const unsigned char src[syw][sxw][scw],
|
||||
long syn, long sxn, long sy0, long sx0, long sc0) {
|
||||
long y, x, c;
|
||||
for (y = 0; y < dyn; ++y) {
|
||||
for (x = 0; x < dxn; ++x) {
|
||||
for (c = 0; c < dcn; ++c) {
|
||||
dst[c][y][x] = src[sy0 + y][sx0 + x][sc0 + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void CompressRange(long cn, long yn, long xn,
|
||||
unsigned char img[cn][yn][xn]) {
|
||||
static const char R[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
double f;
|
||||
long c, y, x, L, H;
|
||||
L = R[0], H = R[strlen(R) - 1];
|
||||
for (c = 0; c < cn; ++c) {
|
||||
for (y = 0; y < yn; ++y) {
|
||||
for (x = 0; x < xn; ++x) {
|
||||
f = img[c][y][x];
|
||||
f /= 255;
|
||||
f *= H - L;
|
||||
f += L;
|
||||
img[c][y][x] = MIN(H, MAX(L, lround(f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintCode(FILE *f, long cn, long yn, long xn,
|
||||
unsigned char img[cn][yn][xn]) {
|
||||
long c, y, x;
|
||||
if (flags_.c) CompressRange(cn, yn, xn, img);
|
||||
for (c = 0; c < cn; ++c) {
|
||||
fputc('\n', f);
|
||||
for (y = 0; y < yn; ++y) {
|
||||
fputc('\n', f);
|
||||
for (x = 0; x < xn; ++x) {
|
||||
fputwc(bing(img[c][y][x], 0), f);
|
||||
}
|
||||
}
|
||||
}
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
static void ProcessImage(const char *path, long scn, long syn, long sxn,
|
||||
unsigned char img[syn][sxn][scn], FILE *f) {
|
||||
double ry, rx;
|
||||
long dyn, dxn, cn;
|
||||
GetOutputGeometry(syn, sxn, &dyn, &dxn, &ry, &rx);
|
||||
if (dyn == syn && dxn == sxn) {
|
||||
/* TODO(jart): Why doesn't Gyarados no-op? */
|
||||
PrintCode(f, scn, dyn, dxn,
|
||||
Deinterlace(scn, syn, sxn, gc(memalign(32, scn * syn * sxn)), syn,
|
||||
sxn, scn, img, syn, sxn, 0, 0, 0));
|
||||
} else {
|
||||
PrintCode(
|
||||
f, scn, dyn, dxn,
|
||||
EzGyarados(scn, dyn, dxn, gc(memalign(32, scn * dyn * dxn)), scn, syn,
|
||||
sxn,
|
||||
Deinterlace(scn, syn, sxn, gc(memalign(32, scn * syn * sxn)),
|
||||
syn, sxn, scn, img, syn, sxn, 0, 0, 0),
|
||||
0, scn, dyn, dxn, syn, sxn, ry, rx, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void WithImageFile(const char *path, FILE *f,
|
||||
void fn(const char *path, long cn, long yn, long xn,
|
||||
unsigned char src[yn][xn][cn], FILE *f)) {
|
||||
struct stat st;
|
||||
void *map, *data;
|
||||
int fd, yn, xn, cn;
|
||||
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_GT(st.st_size, 0);
|
||||
CHECK_LE(st.st_size, INT_MAX);
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
CHECK_NOTNULL(
|
||||
(data = stbi_load_from_memory(map, st.st_size, &xn, &yn, &cn, 0)), "%s",
|
||||
path);
|
||||
CHECK_NE(-1, munmap(map, st.st_size));
|
||||
CHECK_NE(-1, close(fd));
|
||||
fn(path, cn, yn, xn, data, f);
|
||||
free(data);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
FILE *f;
|
||||
showcrashreports();
|
||||
GetOpts(&argc, argv);
|
||||
stbi_set_unpremultiply_on_load(true);
|
||||
CHECK_NOTNULL((f = fopen(flags_.o, "w")));
|
||||
for (i = optind; i < argc; ++i) {
|
||||
WithImageFile(argv[i], f, ProcessImage);
|
||||
}
|
||||
return fclose(f);
|
||||
}
|
58
tool/build/lib/buildlib.mk
Normal file
58
tool/build/lib/buildlib.mk
Normal file
|
@ -0,0 +1,58 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_BUILD_LIB
|
||||
|
||||
TOOL_BUILD_LIB_ARTIFACTS += TOOL_BUILD_LIB_A
|
||||
TOOL_BUILD_LIB = $(TOOL_BUILD_LIB_A_DEPS) $(TOOL_BUILD_LIB_A)
|
||||
TOOL_BUILD_LIB_A = o/$(MODE)/tool/build/lib/buildlib.a
|
||||
TOOL_BUILD_LIB_A_FILES := $(wildcard tool/build/lib/*)
|
||||
TOOL_BUILD_LIB_A_HDRS = $(filter %.h,$(TOOL_BUILD_LIB_A_FILES))
|
||||
TOOL_BUILD_LIB_A_SRCS_S = $(filter %.S,$(TOOL_BUILD_LIB_A_FILES))
|
||||
TOOL_BUILD_LIB_A_SRCS_C = $(filter %.c,$(TOOL_BUILD_LIB_A_FILES))
|
||||
TOOL_BUILD_LIB_A_CHECKS = $(TOOL_BUILD_LIB_A).pkg
|
||||
|
||||
TOOL_BUILD_LIB_A_SRCS = \
|
||||
$(TOOL_BUILD_LIB_A_SRCS_S) \
|
||||
$(TOOL_BUILD_LIB_A_SRCS_C)
|
||||
|
||||
TOOL_BUILD_LIB_A_OBJS = \
|
||||
$(TOOL_BUILD_LIB_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(TOOL_BUILD_LIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_BUILD_LIB_A_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_LOG \
|
||||
LIBC_X
|
||||
|
||||
TOOL_BUILD_LIB_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_BUILD_LIB_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(TOOL_BUILD_LIB_A): \
|
||||
tool/build/lib/ \
|
||||
$(TOOL_BUILD_LIB_A).pkg \
|
||||
$(TOOL_BUILD_LIB_A_OBJS)
|
||||
|
||||
$(TOOL_BUILD_LIB_A).pkg: \
|
||||
$(TOOL_BUILD_LIB_A_OBJS) \
|
||||
$(foreach x,$(TOOL_BUILD_LIB_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
TOOL_BUILD_LIB_LIBS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)))
|
||||
TOOL_BUILD_LIB_SRCS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_SRCS))
|
||||
TOOL_BUILD_LIB_HDRS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_HDRS))
|
||||
TOOL_BUILD_LIB_BINS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_BINS))
|
||||
TOOL_BUILD_LIB_CHECKS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_CHECKS))
|
||||
TOOL_BUILD_LIB_OBJS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_OBJS))
|
||||
TOOL_BUILD_LIB_TESTS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_TESTS))
|
||||
|
||||
.PHONY: o/$(MODE)/tool/build/lib
|
||||
o/$(MODE)/tool/build/lib: $(TOOL_BUILD_LIB_CHECKS)
|
259
tool/build/lib/elfwriter.c
Normal file
259
tool/build/lib/elfwriter.c
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/mappings.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/mremap.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
#include "tool/build/lib/interner.h"
|
||||
|
||||
static const Elf64_Ehdr kObjHeader = {
|
||||
.e_ident = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS64, ELFDATA2LSB, 1,
|
||||
ELFOSABI_NONE},
|
||||
.e_type = ET_REL,
|
||||
.e_machine = EM_NEXGEN32E,
|
||||
.e_version = 1,
|
||||
.e_ehsize = sizeof(Elf64_Ehdr),
|
||||
.e_shentsize = sizeof(Elf64_Shdr)};
|
||||
|
||||
static size_t AppendSection(struct ElfWriter *elf, const char *name,
|
||||
int sh_type, int sh_flags) {
|
||||
ssize_t section =
|
||||
append(elf->shdrs,
|
||||
(&(Elf64_Shdr){.sh_type = sh_type,
|
||||
.sh_flags = sh_flags,
|
||||
.sh_entsize = elf->entsize,
|
||||
.sh_addralign = elf->addralign,
|
||||
.sh_offset = sh_type != SHT_NULL ? elf->wrote : 0,
|
||||
.sh_name = intern(elf->shstrtab, name)}));
|
||||
CHECK_NE(-1, section);
|
||||
return section;
|
||||
}
|
||||
|
||||
static size_t FinishSection(struct ElfWriter *elf) {
|
||||
size_t section = elf->shdrs->i - 1;
|
||||
elf->shdrs->p[section].sh_size =
|
||||
elf->wrote - elf->shdrs->p[section].sh_offset;
|
||||
return section;
|
||||
}
|
||||
|
||||
static struct ElfWriterSymRef AppendSymbol(struct ElfWriter *elf,
|
||||
const char *name, int st_info,
|
||||
int st_other, size_t st_value,
|
||||
size_t st_size, size_t st_shndx,
|
||||
enum ElfWriterSymOrder slg) {
|
||||
ssize_t sym =
|
||||
append(elf->syms[slg], (&(Elf64_Sym){.st_info = st_info,
|
||||
.st_size = st_size,
|
||||
.st_value = st_value,
|
||||
.st_other = st_other,
|
||||
.st_name = intern(elf->strtab, name),
|
||||
.st_shndx = st_shndx}));
|
||||
CHECK_NE(-1, sym);
|
||||
return (struct ElfWriterSymRef){.slg = slg, .sym = sym};
|
||||
}
|
||||
|
||||
static void MakeRelaSection(struct ElfWriter *elf, size_t section) {
|
||||
size_t shdr, size;
|
||||
size = (elf->relas->i - elf->relas->j) * sizeof(Elf64_Rela);
|
||||
elfwriter_align(elf, alignof(Elf64_Rela), sizeof(Elf64_Rela));
|
||||
shdr = elfwriter_startsection(
|
||||
elf,
|
||||
gc(xasprintf("%s%s", ".rela",
|
||||
&elf->shstrtab->p[elf->shdrs->p[section].sh_name])),
|
||||
SHT_RELA, SHF_INFO_LINK);
|
||||
elf->shdrs->p[shdr].sh_info = section;
|
||||
elfwriter_reserve(elf, size);
|
||||
elfwriter_commit(elf, size);
|
||||
FinishSection(elf);
|
||||
elf->relas->j = elf->relas->i;
|
||||
}
|
||||
|
||||
static void WriteRelaSections(struct ElfWriter *elf, size_t symtab) {
|
||||
uint32_t sym;
|
||||
size_t i, j, k;
|
||||
Elf64_Rela *rela;
|
||||
for (j = 0, i = 0; i < elf->shdrs->i; ++i) {
|
||||
if (elf->shdrs->p[i].sh_type == SHT_RELA) {
|
||||
elf->shdrs->p[i].sh_link = symtab;
|
||||
for (rela = (Elf64_Rela *)((char *)elf->map + elf->shdrs->p[i].sh_offset);
|
||||
rela <
|
||||
(Elf64_Rela *)((char *)elf->map + (elf->shdrs->p[i].sh_offset +
|
||||
elf->shdrs->p[i].sh_size));
|
||||
rela++, j++) {
|
||||
sym = elf->relas->p[j].symkey.sym;
|
||||
for (k = 0; k < elf->relas->p[j].symkey.slg; ++k) {
|
||||
sym += elf->syms[k]->i;
|
||||
}
|
||||
rela->r_offset = elf->relas->p[j].offset;
|
||||
rela->r_info = ELF64_R_INFO(sym, elf->relas->p[j].type);
|
||||
rela->r_addend = elf->relas->p[j].addend;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(j == elf->relas->i);
|
||||
}
|
||||
|
||||
static size_t FlushStrtab(struct ElfWriter *elf, const char *name,
|
||||
struct Interner *strtab) {
|
||||
size_t size = strtab->i * sizeof(strtab->p[0]);
|
||||
elfwriter_align(elf, 1, 0);
|
||||
AppendSection(elf, ".strtab", SHT_STRTAB, 0);
|
||||
mempcpy(elfwriter_reserve(elf, size), strtab->p, size);
|
||||
elfwriter_commit(elf, size);
|
||||
return FinishSection(elf);
|
||||
}
|
||||
|
||||
static void FlushTables(struct ElfWriter *elf) {
|
||||
size_t i, size, symtab;
|
||||
elfwriter_align(elf, alignof(Elf64_Sym), sizeof(Elf64_Sym));
|
||||
symtab = AppendSection(elf, ".symtab", SHT_SYMTAB, 0);
|
||||
for (i = 0; i < ARRAYLEN(elf->syms); ++i) {
|
||||
size = elf->syms[i]->i * sizeof(Elf64_Sym);
|
||||
memcpy(elfwriter_reserve(elf, size), elf->syms[i]->p, size);
|
||||
elfwriter_commit(elf, size);
|
||||
}
|
||||
FinishSection(elf);
|
||||
elf->shdrs->p[symtab].sh_link = FlushStrtab(elf, ".strtab", elf->strtab);
|
||||
elf->ehdr->e_shstrndx = FlushStrtab(elf, ".shstrtab", elf->shstrtab);
|
||||
WriteRelaSections(elf, symtab);
|
||||
size = elf->shdrs->i * sizeof(elf->shdrs->p[0]);
|
||||
elfwriter_align(elf, alignof(elf->shdrs->p[0]), sizeof(elf->shdrs->p[0]));
|
||||
elf->ehdr->e_shoff = elf->wrote;
|
||||
elf->ehdr->e_shnum = elf->shdrs->i;
|
||||
elf->shdrs->p[symtab].sh_info =
|
||||
elf->syms[kElfWriterSymSection]->i + elf->syms[kElfWriterSymLocal]->i;
|
||||
mempcpy(elfwriter_reserve(elf, size), elf->shdrs->p, size);
|
||||
elfwriter_commit(elf, size);
|
||||
}
|
||||
|
||||
struct ElfWriter *elfwriter_open(const char *path, int mode) {
|
||||
struct ElfWriter *elf;
|
||||
CHECK_NOTNULL((elf = calloc(1, sizeof(struct ElfWriter))));
|
||||
CHECK_NOTNULL((elf->path = strdup(path)));
|
||||
CHECK_NE(-1, asprintf(&elf->tmppath, "%s.%d", elf->path, getpid()));
|
||||
CHECK_NE(-1, (elf->fd = open(elf->tmppath,
|
||||
O_CREAT | O_TRUNC | O_RDWR | O_EXCL, mode)));
|
||||
CHECK_NE(-1, ftruncate(elf->fd, (elf->mapsize = FRAMESIZE)));
|
||||
CHECK_NE(MAP_FAILED, (elf->map = mmap((void *)(intptr_t)kFixedMappingsStart,
|
||||
elf->mapsize, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_FIXED, elf->fd, 0)));
|
||||
elf->ehdr = memcpy(elf->map, &kObjHeader, (elf->wrote = sizeof(kObjHeader)));
|
||||
elf->strtab = newinterner();
|
||||
elf->shstrtab = newinterner();
|
||||
return elf;
|
||||
}
|
||||
|
||||
void elfwriter_close(struct ElfWriter *elf) {
|
||||
size_t i;
|
||||
FlushTables(elf);
|
||||
CHECK_NE(-1, munmap(elf->map, elf->mapsize));
|
||||
CHECK_NE(-1, ftruncate(elf->fd, elf->wrote));
|
||||
CHECK_NE(-1, close(elf->fd));
|
||||
CHECK_NE(-1, rename(elf->tmppath, elf->path));
|
||||
freeinterner(elf->shstrtab);
|
||||
freeinterner(elf->strtab);
|
||||
free(elf->shdrs->p);
|
||||
free(elf->relas->p);
|
||||
for (i = 0; i < ARRAYLEN(elf->syms); ++i) free(elf->syms[i]->p);
|
||||
free(elf);
|
||||
}
|
||||
|
||||
void elfwriter_align(struct ElfWriter *elf, size_t addralign, size_t entsize) {
|
||||
elf->entsize = entsize;
|
||||
elf->addralign = addralign;
|
||||
elf->wrote = roundup(elf->wrote, addralign);
|
||||
}
|
||||
|
||||
size_t elfwriter_startsection(struct ElfWriter *elf, const char *name,
|
||||
int sh_type, int sh_flags) {
|
||||
size_t shdr = AppendSection(elf, name, sh_type, sh_flags);
|
||||
AppendSymbol(elf, "",
|
||||
sh_type != SHT_NULL ? ELF64_ST_INFO(STB_LOCAL, STT_SECTION)
|
||||
: ELF64_ST_INFO(STB_LOCAL, STT_NOTYPE),
|
||||
STV_DEFAULT, 0, 0, shdr, kElfWriterSymSection);
|
||||
return shdr;
|
||||
}
|
||||
|
||||
void *elfwriter_reserve(struct ElfWriter *elf, size_t size) {
|
||||
size_t need, greed;
|
||||
need = elf->wrote + size;
|
||||
greed = elf->mapsize;
|
||||
if (need > greed) {
|
||||
do {
|
||||
greed = greed + (greed >> 1);
|
||||
} while (need > greed);
|
||||
greed = roundup(greed, FRAMESIZE);
|
||||
CHECK_NE(-1, ftruncate(elf->fd, greed));
|
||||
CHECK_NE(MAP_FAILED, mmap((char *)elf->map + elf->mapsize,
|
||||
greed - elf->mapsize, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_FIXED, elf->fd, elf->mapsize));
|
||||
elf->mapsize = greed;
|
||||
}
|
||||
return (char *)elf->map + elf->wrote;
|
||||
}
|
||||
|
||||
void elfwriter_commit(struct ElfWriter *elf, size_t size) {
|
||||
elf->wrote += size;
|
||||
}
|
||||
|
||||
void elfwriter_finishsection(struct ElfWriter *elf) {
|
||||
size_t section = FinishSection(elf);
|
||||
if (elf->relas->j < elf->relas->i) MakeRelaSection(elf, section);
|
||||
}
|
||||
|
||||
struct ElfWriterSymRef elfwriter_appendsym(struct ElfWriter *elf,
|
||||
const char *name, int st_info,
|
||||
int st_other, size_t st_value,
|
||||
size_t st_size) {
|
||||
return AppendSymbol(
|
||||
elf, name, st_info, st_other, st_value, st_size, elf->shdrs->i - 1,
|
||||
ELF64_ST_BIND(st_info) == STB_LOCAL ? kElfWriterSymLocal
|
||||
: kElfWriterSymGlobal);
|
||||
}
|
||||
|
||||
struct ElfWriterSymRef elfwriter_linksym(struct ElfWriter *elf,
|
||||
const char *name, int st_info,
|
||||
int st_other) {
|
||||
return AppendSymbol(elf, name, st_info, st_other, 0, 0, 0,
|
||||
kElfWriterSymGlobal);
|
||||
}
|
||||
|
||||
void elfwriter_appendrela(struct ElfWriter *elf, uint64_t r_offset,
|
||||
struct ElfWriterSymRef symkey, uint32_t type,
|
||||
int64_t r_addend) {
|
||||
CHECK_NE(-1,
|
||||
append(elf->relas, (&(struct ElfWriterRela){.type = type,
|
||||
.symkey = symkey,
|
||||
.offset = r_offset,
|
||||
.addend = r_addend})));
|
||||
}
|
67
tool/build/lib/elfwriter.h
Normal file
67
tool/build/lib/elfwriter.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ELFWRITER_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ELFWRITER_H_
|
||||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "libc/elf/struct/rela.h"
|
||||
#include "libc/elf/struct/shdr.h"
|
||||
#include "libc/elf/struct/sym.h"
|
||||
#include "tool/build/lib/interner.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct ElfWriter {
|
||||
char *path;
|
||||
char *tmppath;
|
||||
int fd;
|
||||
void *map;
|
||||
size_t mapsize;
|
||||
size_t wrote;
|
||||
size_t entsize;
|
||||
size_t addralign;
|
||||
struct Elf64_Ehdr *ehdr;
|
||||
struct {
|
||||
size_t i, n;
|
||||
Elf64_Shdr *p;
|
||||
} shdrs[1];
|
||||
struct ElfWriterSyms {
|
||||
size_t i, n;
|
||||
Elf64_Sym *p;
|
||||
} syms[3][1];
|
||||
struct {
|
||||
size_t i, j, n;
|
||||
struct ElfWriterRela {
|
||||
uint64_t offset;
|
||||
struct ElfWriterSymRef {
|
||||
enum ElfWriterSymOrder {
|
||||
kElfWriterSymSection,
|
||||
kElfWriterSymLocal,
|
||||
kElfWriterSymGlobal
|
||||
} slg;
|
||||
uint32_t sym;
|
||||
} symkey;
|
||||
uint32_t type;
|
||||
int64_t addend;
|
||||
} * p;
|
||||
} relas[1];
|
||||
struct Interner *strtab;
|
||||
struct Interner *shstrtab;
|
||||
};
|
||||
|
||||
struct ElfWriter *elfwriter_open(const char *, int) nodiscard;
|
||||
void elfwriter_cargoculting(struct ElfWriter *);
|
||||
void elfwriter_close(struct ElfWriter *);
|
||||
void elfwriter_align(struct ElfWriter *, size_t, size_t);
|
||||
size_t elfwriter_startsection(struct ElfWriter *, const char *, int, int);
|
||||
void *elfwriter_reserve(struct ElfWriter *, size_t);
|
||||
void elfwriter_commit(struct ElfWriter *, size_t);
|
||||
void elfwriter_finishsection(struct ElfWriter *);
|
||||
void elfwriter_appendrela(struct ElfWriter *, uint64_t, struct ElfWriterSymRef,
|
||||
uint32_t, int64_t);
|
||||
struct ElfWriterSymRef elfwriter_linksym(struct ElfWriter *, const char *, int,
|
||||
int);
|
||||
struct ElfWriterSymRef elfwriter_appendsym(struct ElfWriter *, const char *,
|
||||
int, int, size_t, size_t);
|
||||
void elfwriter_yoink(struct ElfWriter *, const char *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ELFWRITER_H_ */
|
31
tool/build/lib/elfwriter_cargoculting.c
Normal file
31
tool/build/lib/elfwriter_cargoculting.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/elf/def.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
|
||||
void elfwriter_cargoculting(struct ElfWriter *elf) {
|
||||
elfwriter_startsection(elf, "", SHT_NULL, 0);
|
||||
elfwriter_startsection(elf, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
|
||||
elfwriter_finishsection(elf);
|
||||
elfwriter_startsection(elf, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
||||
elfwriter_finishsection(elf);
|
||||
elfwriter_startsection(elf, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
||||
elfwriter_finishsection(elf);
|
||||
}
|
33
tool/build/lib/elfwriter_yoink.c
Normal file
33
tool/build/lib/elfwriter_yoink.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
|
||||
void elfwriter_yoink(struct ElfWriter *elf, const char *symbol) {
|
||||
unsigned char *p;
|
||||
struct ElfWriterSymRef sym;
|
||||
const unsigned char nopl[8] = "\x0f\x1f\x04\x25\x00\x00\x00\x00";
|
||||
p = elfwriter_reserve(elf, 8);
|
||||
memcpy(p, nopl, sizeof(nopl));
|
||||
sym = elfwriter_linksym(elf, symbol, ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
||||
STV_HIDDEN);
|
||||
elfwriter_appendrela(elf, sizeof(nopl) - 4, sym, R_X86_64_32, 0);
|
||||
elfwriter_commit(elf, sizeof(nopl));
|
||||
}
|
134
tool/build/lib/interner.c
Normal file
134
tool/build/lib/interner.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/knuthmultiplicativehash.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/interner.h"
|
||||
|
||||
#define kInitialItems 16
|
||||
|
||||
struct InternerObject {
|
||||
struct Interner pool;
|
||||
size_t i, n;
|
||||
struct InternerHash {
|
||||
unsigned hash; /* 0 means empty */
|
||||
unsigned index;
|
||||
} * p;
|
||||
};
|
||||
|
||||
static void rehash(struct InternerObject *it) {
|
||||
size_t i, j, n, step;
|
||||
struct InternerHash *p;
|
||||
n = it->n;
|
||||
p = it->p;
|
||||
it->p = xcalloc((it->n <<= 1), sizeof(struct InternerHash));
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!p[i].hash) continue;
|
||||
step = 0;
|
||||
do {
|
||||
j = (p[i].hash + step * (step + 1) / 2) & (it->n - 1);
|
||||
step++;
|
||||
} while (it->p[j].hash);
|
||||
memcpy(&it->p[j], &p[i], sizeof(p[i]));
|
||||
}
|
||||
free_s(&p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new interner.
|
||||
*/
|
||||
struct Interner *newinterner(void) {
|
||||
struct InternerObject *it;
|
||||
it = xcalloc(1, sizeof(*it));
|
||||
it->p = xcalloc((it->n = kInitialItems), sizeof(*it->p));
|
||||
it->pool.p = xcalloc((it->pool.n = kInitialItems), sizeof(*it->pool.p));
|
||||
return &it->pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys interner.
|
||||
*/
|
||||
void freeinterner(struct Interner *t) {
|
||||
struct InternerObject *it = (struct InternerObject *)t;
|
||||
if (it) {
|
||||
free(it->pool.p);
|
||||
free(it->p);
|
||||
free(it);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of unique items interned.
|
||||
*/
|
||||
size_t interncount(const struct Interner *t) {
|
||||
struct InternerObject *it = (struct InternerObject *)t;
|
||||
return it->i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interns object.
|
||||
*
|
||||
* @return index into 𝑡→𝑝 holding equal item
|
||||
* @note use consistent size w/ non-string items
|
||||
*/
|
||||
size_t internobj(struct Interner *t, const void *data, size_t size) {
|
||||
struct InternerObject *it = (struct InternerObject *)t;
|
||||
unsigned hash;
|
||||
size_t i, step;
|
||||
unsigned char *item;
|
||||
step = 0;
|
||||
item = data;
|
||||
hash = max(1, KnuthMultiplicativeHash32(data, size));
|
||||
do {
|
||||
/* it is written that triangle probe halts iff i<n/2 && popcount(n)==1 */
|
||||
i = (hash + step * (step + 1) / 2) & (it->n - 1);
|
||||
if (it->p[i].hash == hash && it->p[i].index + size <= it->pool.n &&
|
||||
memcmp(item, &it->pool.p[it->p[i].index], size) == 0) {
|
||||
return it->p[i].index;
|
||||
}
|
||||
step++;
|
||||
} while (it->p[i].hash);
|
||||
if (++it->i == (it->n >> 1)) {
|
||||
rehash(it);
|
||||
step = 0;
|
||||
do {
|
||||
i = (hash + step * (step + 1) / 2) & (it->n - 1);
|
||||
step++;
|
||||
} while (it->p[i].hash);
|
||||
}
|
||||
it->p[i].hash = hash;
|
||||
return (it->p[i].index = concat(&it->pool, item, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Interns string.
|
||||
*
|
||||
* The NUL-terminated string 𝑠 is concatenated to the relocatable
|
||||
* double-NUL terminated string list 𝑡→𝑝 with de-duplication and
|
||||
* preservation of insertion order.
|
||||
*
|
||||
* @return index into 𝑡→𝑝 holding string equal to 𝑠
|
||||
*/
|
||||
size_t intern(struct Interner *t, const char *s) {
|
||||
return internobj(t, s, strlen(s) + 1);
|
||||
}
|
20
tool/build/lib/interner.h
Normal file
20
tool/build/lib/interner.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_INTERNER_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_INTERNER_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Interner {
|
||||
size_t i; /* byte size of 𝑝 */
|
||||
size_t n; /* byte capacity of 𝑝 */
|
||||
char *p; /* will relocate */
|
||||
};
|
||||
|
||||
struct Interner *newinterner(void) returnsnonnull paramsnonnull();
|
||||
void freeinterner(struct Interner *);
|
||||
size_t interncount(const struct Interner *) paramsnonnull();
|
||||
size_t internobj(struct Interner *, const void *, size_t) paramsnonnull();
|
||||
size_t intern(struct Interner *, const char *) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_INTERNER_H_ */
|
123
tool/build/lib/persist.c
Normal file
123
tool/build/lib/persist.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/persist.h"
|
||||
|
||||
static bool IsWithin(size_t sz1, void *vp1, size_t sz2, void *vp2) {
|
||||
char *p1 = vp1, *p2 = vp2;
|
||||
return p1 >= p2 && p1 + sz1 <= p2 + sz2;
|
||||
}
|
||||
|
||||
static bool IsOverlapping(void *vx1, void *vy1, void *vx2, void *vy2) {
|
||||
char *x1 = vx1, *y1 = vy1, *x2 = vx2, *y2 = vy2;
|
||||
return (x1 >= x2 && x1 <= y2) || (y1 >= x2 && y1 <= y2);
|
||||
}
|
||||
|
||||
static bool IsOverlappingIov(struct iovec *a, struct iovec *b) {
|
||||
char *ap = a->iov_base, *bp = b->iov_base;
|
||||
return IsOverlapping(ap, ap + a->iov_len, bp, bp + b->iov_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes struct w/ dynamic arrays to mappable file, e.g.
|
||||
*
|
||||
* PersistObject(path, 64, &(struct ObjectParam){
|
||||
* sizeof(*o), o, &o->magic, &o->abi,
|
||||
* &(struct ObjectArrayParam){
|
||||
* {&o->a1.i, sizeof(o->a1.p[0]), &o->a1.p},
|
||||
* {&o->a2.i, sizeof(o->a2.p[0]), &o->a2.p},
|
||||
* {0},
|
||||
* }});
|
||||
*
|
||||
* @param obj->magic needs to be unique for struct
|
||||
* @param obj->abi monotonically tracks breaking changes
|
||||
* @param obj->arrays needs sentinel with item size of zero
|
||||
* @note non-recursive i.e. array elements can't have pointers
|
||||
* @see MapObject()
|
||||
*/
|
||||
void PersistObject(const char *path, size_t align,
|
||||
const struct ObjectParam *obj) {
|
||||
struct iovec *iov;
|
||||
int i, n, fd, iovlen;
|
||||
const char *tmp, *pad;
|
||||
long len, size, bytes, filesize;
|
||||
unsigned char *hdr, *p1, *p2, **pp;
|
||||
intptr_t arrayptroffset, arraydataoffset;
|
||||
filesize = 0;
|
||||
DCHECK_GE(align, 1);
|
||||
CHECK_GT(*obj->magic, 0);
|
||||
CHECK_GT(*obj->abi, 0);
|
||||
CHECK(IsWithin(sizeof(*obj->magic), obj->magic, obj->size, obj->p));
|
||||
CHECK(IsWithin(sizeof(*obj->abi), obj->abi, obj->size, obj->p));
|
||||
for (n = i = 0; obj->arrays[i].size; ++i) ++n;
|
||||
iovlen = (n + 1) * 2;
|
||||
pad = gc(xcalloc(align, 1));
|
||||
hdr = gc(xmalloc(obj->size));
|
||||
iov = gc(xcalloc(iovlen, sizeof(*iov)));
|
||||
tmp = gc(xasprintf("%s.%d.%s", path, getpid(), "tmp"));
|
||||
bytes = obj->size;
|
||||
iov[0].iov_base = memcpy(hdr, obj->p, obj->size);
|
||||
iov[0].iov_len = bytes;
|
||||
iov[1].iov_base = pad;
|
||||
iov[1].iov_len = ROUNDUP(bytes, align) - bytes;
|
||||
filesize += ROUNDUP(bytes, align);
|
||||
for (i = 0; i < n; ++i) {
|
||||
pp = obj->arrays[i].pp;
|
||||
len = obj->arrays[i].len;
|
||||
size = obj->arrays[i].size;
|
||||
if (!*pp || !len) continue;
|
||||
p1 = obj->p;
|
||||
p2 = obj->arrays[i].pp;
|
||||
arrayptroffset = p2 - p1;
|
||||
arraydataoffset = filesize;
|
||||
CHECK((!len || bsrl(len) + bsrl(size) < 31),
|
||||
"path=%s i=%d len=%,lu size=%,lu", path, i, len, size);
|
||||
CHECK(IsWithin(sizeof(void *), pp, obj->size, obj->p));
|
||||
CHECK(!IsOverlapping(pp, pp + sizeof(void *), obj->magic,
|
||||
obj->magic + sizeof(*obj->magic)));
|
||||
CHECK(!IsOverlapping(pp, pp + sizeof(void *), obj->abi,
|
||||
obj->abi + sizeof(*obj->abi)));
|
||||
memcpy(hdr + arrayptroffset, &arraydataoffset, sizeof(intptr_t));
|
||||
CHECK_LT(filesize + arraydataoffset, 0x7ffff000);
|
||||
bytes = len * size;
|
||||
iov[(i + 1) * 2 + 0].iov_base = *pp;
|
||||
iov[(i + 1) * 2 + 0].iov_len = bytes;
|
||||
iov[(i + 1) * 2 + 1].iov_base = pad;
|
||||
iov[(i + 1) * 2 + 1].iov_len = ROUNDUP(bytes, align) - bytes;
|
||||
filesize += ROUNDUP(bytes, align);
|
||||
CHECK(!IsOverlappingIov(&iov[(i + 0) * 2], &iov[(i + 1) * 2]),
|
||||
"iov[%d]={%#p,%#x}, iov[%d]={%#p,%#x} path=%s", (i + 0) * 2,
|
||||
iov[(i + 0) * 2].iov_base, iov[(i + 0) * 2].iov_len, (i + 1) * 2,
|
||||
iov[(i + 1) * 2].iov_base, iov[(i + 1) * 2].iov_len, path);
|
||||
}
|
||||
CHECK_NE(-1, (fd = open(tmp, O_CREAT | O_WRONLY | O_EXCL, 0644)), "%s", tmp);
|
||||
CHECK_EQ(filesize, writev(fd, iov, iovlen));
|
||||
CHECK_NE(-1, close(fd));
|
||||
CHECK_NE(-1, rename(tmp, path), "%s", path);
|
||||
}
|
22
tool/build/lib/persist.h
Normal file
22
tool/build/lib/persist.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct ObjectParam {
|
||||
size_t size;
|
||||
void *p;
|
||||
uint32_t *magic;
|
||||
int32_t *abi;
|
||||
struct ObjectArrayParam {
|
||||
size_t len;
|
||||
size_t size;
|
||||
void *pp;
|
||||
} * arrays;
|
||||
};
|
||||
|
||||
void PersistObject(const char *, size_t, const struct ObjectParam *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_ */
|
184
tool/build/lz4toasm.c
Normal file
184
tool/build/lz4toasm.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/kompressor.h"
|
||||
#include "libc/nexgen32e/lz4.h"
|
||||
#include "libc/runtime/ezmap.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
/**
|
||||
* @fileoverview LZ4 content embedder.
|
||||
*
|
||||
* This tool converts an LZ4-compressed file into assembly source code,
|
||||
* that will appear to C/C++ code as a global constant holding the
|
||||
* uncompressed contents, which is unpacked automatically.
|
||||
*
|
||||
* @note this is a build tool that assumes input data is trustworthy
|
||||
*/
|
||||
|
||||
#define COLS 8
|
||||
|
||||
struct stat st_;
|
||||
size_t extractedsize;
|
||||
|
||||
noreturn void usage(char *argv[], FILE *f, int rc) {
|
||||
fprintf(f, "%s: %s [-o %s] [-s %s] %s\n", "Usage", argv[0], "PATH", "SYMBOL",
|
||||
"FILE");
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *symbol = "kData";
|
||||
const char *lz4path = "/dev/stdin";
|
||||
const char *outpath = "/dev/stdout";
|
||||
const char *initprio = "400,_init_";
|
||||
const unsigned char *lz4data;
|
||||
int opt;
|
||||
FILE *fin, *fout;
|
||||
|
||||
showcrashreports();
|
||||
|
||||
while ((opt = getopt(argc, argv, "ho:s:z:")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
symbol = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
outpath = optarg;
|
||||
break;
|
||||
case 'z':
|
||||
extractedsize = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
usage(argv, stdout, 0);
|
||||
default:
|
||||
usage(argv, stderr, 1);
|
||||
}
|
||||
}
|
||||
if (argc - optind) {
|
||||
lz4path = argv[optind];
|
||||
}
|
||||
|
||||
CHECK_NOTNULL((fin = fopen(lz4path, "r")));
|
||||
CHECK_NE(-1, fstat(fileno(fin), &st_));
|
||||
CHECK_NOTNULL((lz4data = malloc(st_.st_size)));
|
||||
CHECK_EQ(1, fread(lz4data, st_.st_size, 1, fin));
|
||||
CHECK_NE(-1, fclose(fin));
|
||||
|
||||
CHECK_NOTNULL((fout = fopen(outpath, "w")));
|
||||
|
||||
CHECK_EQ(LZ4_MAGICNUMBER, LZ4_MAGIC(lz4data));
|
||||
CHECK_EQ(1, LZ4_FRAME_VERSION(lz4data));
|
||||
|
||||
const unsigned char *frame = /* lz4check( */ lz4data /* ) */;
|
||||
const unsigned char *block1 = frame + LZ4_FRAME_HEADERSIZE(frame);
|
||||
const unsigned char *block2 = block1 + LZ4_BLOCK_SIZE(frame, block1);
|
||||
CHECK(LZ4_BLOCK_ISCOMPRESSED(block1));
|
||||
CHECK(LZ4_BLOCK_ISEOF(block2));
|
||||
const unsigned char *data = LZ4_BLOCK_DATA(block1);
|
||||
size_t size = LZ4_BLOCK_DATASIZE(block1);
|
||||
|
||||
fprintf(fout,
|
||||
"/\t%s -o %s -s %s %s\n"
|
||||
".include \"libc/macros.inc\"\n"
|
||||
"\n",
|
||||
argv[0], outpath, symbol, lz4path);
|
||||
|
||||
if (!extractedsize) {
|
||||
if (LZ4_FRAME_BLOCKCONTENTSIZEFLAG(frame)) {
|
||||
extractedsize = LZ4_FRAME_BLOCKCONTENTSIZE(frame);
|
||||
} else {
|
||||
fprintf(stderr, "error: need extractedsize\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t bss = ROUNDUP(extractedsize, 8);
|
||||
size_t misalign = bss - extractedsize;
|
||||
|
||||
fprintf(fout, "\t.rodata\n");
|
||||
fprintf(fout, "\t.align\t4\n");
|
||||
fprintf(fout, "%sLen:\n", symbol);
|
||||
fprintf(fout, "\t.long\t%lu\n", extractedsize);
|
||||
fprintf(fout, "\t.endobj\t%sLen,globl,hidden\n", symbol);
|
||||
fprintf(fout, "\t.previous\n");
|
||||
|
||||
fprintf(fout, "\n");
|
||||
fprintf(fout, "\t.initbss %s%s\n", initprio, symbol);
|
||||
fprintf(fout, "%s:\n", symbol);
|
||||
fprintf(fout, "\t.zero\t%lu\n", bss);
|
||||
fprintf(fout, "\t.endobj\t%s,globl,hidden\n", symbol);
|
||||
fprintf(fout, "\t.previous\n");
|
||||
|
||||
fprintf(fout, "\n");
|
||||
fprintf(fout, "\t.init.start %s%s\n", initprio, symbol);
|
||||
fprintf(fout, "\tpush\t%%rsi\n");
|
||||
fprintf(fout, "\tmov\t$%u,%%edx\n", size);
|
||||
fprintf(fout, "\tcall\tlz4cpy\n");
|
||||
if (misalign) {
|
||||
fprintf(fout, "\tlea\t%zu(%%rax),%%rdi\n", misalign);
|
||||
} else {
|
||||
fprintf(fout, "\tmov\t%%rax,%%rdi\n");
|
||||
}
|
||||
fprintf(fout, "\tpop\t%%rsi\n");
|
||||
fprintf(fout, "\tadd\t$%u,%%rsi\n", ROUNDUP(size, 8));
|
||||
fprintf(fout, "\t.init.end %s%s\n", initprio, symbol);
|
||||
|
||||
fprintf(fout, "\n");
|
||||
fprintf(fout, "\t.initro %s%s\n", initprio, symbol);
|
||||
fprintf(fout, "%sLz4:\n", symbol);
|
||||
int col = 0;
|
||||
char16_t glyphs[COLS + 1];
|
||||
for (unsigned i = 0; i < size; ++i) {
|
||||
unsigned char ch = data[i];
|
||||
if (col == 0) {
|
||||
fprintf(fout, "\t.byte\t");
|
||||
memset(glyphs, 0, sizeof(glyphs));
|
||||
}
|
||||
/* TODO(jart): Fix Emacs */
|
||||
glyphs[col] = kCp437[ch == '"' || ch == '#' ? '.' : ch];
|
||||
if (col) fputc(',', fout);
|
||||
fprintf(fout, "0x%02x", ch);
|
||||
if (++col == COLS) {
|
||||
col = 0;
|
||||
fprintf(fout, "\t#%hs\n", glyphs);
|
||||
}
|
||||
}
|
||||
while (col++ != COLS) {
|
||||
fprintf(fout, ",0x00");
|
||||
}
|
||||
fprintf(fout, "\n");
|
||||
fprintf(fout, "\t.endobj\t%sLz4,globl,hidden\n", symbol);
|
||||
fprintf(fout, "\t.previous\n");
|
||||
|
||||
return fclose(fout);
|
||||
}
|
314
tool/build/mkdeps.c
Normal file
314
tool/build/mkdeps.c
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/alg/bisectcarleft.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/ezmap.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/mappings.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Make dependency generator.
|
||||
*
|
||||
* This program generates Makefile code saying which sources include
|
||||
* which headers, thus improving build invalidation.
|
||||
*
|
||||
* The same thing can be accomplished using GCC's -M flag. This tool is
|
||||
* much faster. It's designed to process over 9,000 sources to generate
|
||||
* 50k+ lines of make code in ~80ms using one core and a meg of ram.
|
||||
*/
|
||||
|
||||
static const char *const kSourceExts[] = {".s", ".S", ".c", ".cc", ".cpp"};
|
||||
static alignas(16) const char kIncludePrefix[] = "include \"";
|
||||
|
||||
static const char *const kModelessPackages[] = {
|
||||
"libc/nt/",
|
||||
"libc/stubs/",
|
||||
"libc/sysv/",
|
||||
};
|
||||
|
||||
struct Strings {
|
||||
size_t i, n;
|
||||
char *p;
|
||||
};
|
||||
|
||||
struct Source {
|
||||
uint32_t hash; /* 0 means empty w/ triangle probe */
|
||||
uint32_t name; /* strings.p[name] w/ interning */
|
||||
uint32_t id; /* rehashing changes indexes */
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
int32_t from; /* sources.p[from.id] */
|
||||
int32_t to; /* sources.p[to.id] */
|
||||
};
|
||||
|
||||
struct Sources {
|
||||
size_t i, n; /* phase 1: hashmap: popcount(n)==1 if n */
|
||||
struct Source *p; /* phase 2: arraylist sorted by id */
|
||||
};
|
||||
|
||||
struct Edges {
|
||||
size_t i, n;
|
||||
struct Edge *p;
|
||||
};
|
||||
|
||||
int g_sourceid;
|
||||
struct Strings strings;
|
||||
struct Sources sources;
|
||||
struct Edges edges;
|
||||
const char *buildroot;
|
||||
int *visited;
|
||||
char *out;
|
||||
FILE *fout;
|
||||
|
||||
static int CompareSourcesById(struct Source *a, struct Source *b) {
|
||||
return a->id > b->id ? 1 : a->id < b->id ? -1 : 0;
|
||||
}
|
||||
|
||||
static int CompareEdgesByFrom(struct Edge *a, struct Edge *b) {
|
||||
return a->from > b->from ? 1 : a->from < b->from ? -1 : 0;
|
||||
}
|
||||
|
||||
static uint32_t Hash(const void *s, size_t l) {
|
||||
return max(1, crc32c(0, s, l));
|
||||
}
|
||||
|
||||
void Crunch(void) {
|
||||
size_t i, j;
|
||||
for (i = 0, j = 0; j < sources.n; ++j) {
|
||||
if (!sources.p[j].hash) continue;
|
||||
if (i != j) memcpy(&sources.p[i], &sources.p[j], sizeof(sources.p[j]));
|
||||
i++;
|
||||
}
|
||||
sources.i = i;
|
||||
qsort(sources.p, sources.i, sizeof(*sources.p), (void *)CompareSourcesById);
|
||||
qsort(edges.p, edges.i, sizeof(*edges.p), (void *)CompareEdgesByFrom);
|
||||
}
|
||||
|
||||
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);
|
||||
memcpy(&sources.p[j], &old.p[i], sizeof(old.p[i]));
|
||||
}
|
||||
free(old.p);
|
||||
}
|
||||
|
||||
uint32_t GetSourceId(const char *name, size_t len) {
|
||||
size_t i, step;
|
||||
uint32_t hash = Hash(name, len);
|
||||
if (sources.n) {
|
||||
step = 0;
|
||||
do {
|
||||
i = (hash + step * (step + 1) / 2) & (sources.n - 1);
|
||||
if (sources.p[i].hash == hash &&
|
||||
memcmp(name, &strings.p[sources.p[i].name], len) == 0) {
|
||||
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;
|
||||
sources.p[i].name = concat(&strings, name, len);
|
||||
strings.p[strings.i++] = '\0';
|
||||
return (sources.p[i].id = g_sourceid++);
|
||||
}
|
||||
|
||||
void LoadRelationships(int argc, char *argv[]) {
|
||||
struct MappedFile mf;
|
||||
const char *p, *pe;
|
||||
size_t i, linecap = 0;
|
||||
char *line = NULL;
|
||||
FILE *finpaths;
|
||||
for (i = optind; i < argc; ++i) {
|
||||
CHECK_NOTNULL((finpaths = fopen(argv[i], "r")));
|
||||
while (getline(&line, &linecap, finpaths) != -1) {
|
||||
if (mapfileread(chomp(line), &mf) == -1) {
|
||||
CHECK_EQ(ENOENT, errno, "%s", line);
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
fprintf(stderr, "%s %s...\n", "Refreshing", argv[i]);
|
||||
unlink(argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
if (mf.size) {
|
||||
if (mf.size > PAGESIZE) {
|
||||
madvise(mf.addr, mf.size, MADV_WILLNEED | MADV_SEQUENTIAL);
|
||||
}
|
||||
uint32_t sauce = GetSourceId(line, strlen(line));
|
||||
size_t inclen = strlen(kIncludePrefix);
|
||||
p = mf.addr;
|
||||
pe = p + mf.size;
|
||||
while ((p = strstr(p, kIncludePrefix))) {
|
||||
const char *path = p + inclen;
|
||||
const char *pathend = memchr(path, '"', pe - path);
|
||||
if (pathend && (intptr_t)p > (intptr_t)mf.addr &&
|
||||
(p[-1] == '#' || p[-1] == '.') &&
|
||||
(p - 1 == mf.addr || p[-2] == '\n')) {
|
||||
uint32_t dependency = GetSourceId(path, pathend - path);
|
||||
struct Edge edge;
|
||||
edge.from = sauce;
|
||||
edge.to = dependency;
|
||||
append(&edges, &edge);
|
||||
}
|
||||
p = path;
|
||||
}
|
||||
}
|
||||
CHECK_NE(-1, unmapfile(&mf));
|
||||
}
|
||||
CHECK_NE(-1, fclose(finpaths));
|
||||
}
|
||||
free_s(&line);
|
||||
}
|
||||
|
||||
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:
|
||||
fprintf(stderr, "%s: %s [-r %s] [-o %s] [%s...]\n", "Usage", argv[0],
|
||||
"BUILDROOT", "OUTPUT", "PATHSFILE");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (isempty(out)) fprintf(stderr, "need -o FILE"), exit(1);
|
||||
if (isempty(buildroot)) fprintf(stderr, "need -r o/$(MODE)"), exit(1);
|
||||
}
|
||||
|
||||
const char *StripExt(const char *s) {
|
||||
static bool once;
|
||||
static size_t i, n;
|
||||
static char *p, *dot;
|
||||
if (!once) {
|
||||
once = true;
|
||||
__cxa_atexit(free_s, &p, NULL);
|
||||
}
|
||||
i = 0;
|
||||
CONCAT(&p, &i, &n, s, strlen(s));
|
||||
dot = strrchr(p, '.');
|
||||
if (dot) *dot = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
bool IsObjectSource(const char *name) {
|
||||
for (size_t i = 0; i < ARRAYLEN(kSourceExts); ++i) {
|
||||
if (endswith(name, kSourceExts[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Dive(uint32_t sauce) {
|
||||
for (uint32_t i = bisectcarleft((const int32_t(*)[2])edges.p, edges.i, sauce);
|
||||
edges.p[i].from == sauce; ++i) {
|
||||
int32_t dep = edges.p[i].to;
|
||||
if (bts(visited, dep)) continue;
|
||||
fputs(" \\\n\t", fout);
|
||||
fputs(&strings.p[sources.p[dep].name], fout);
|
||||
Dive(dep);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsModeless(const char *path) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(kModelessPackages); ++i) {
|
||||
if (startswith(path, kModelessPackages[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
out = "/dev/stdout";
|
||||
GetOpts(argc, argv);
|
||||
char *tmp =
|
||||
!fileexists(out) || isregularfile(out) ? xasprintf("%s.tmp", out) : NULL;
|
||||
CHECK_NOTNULL((fout = fopen(tmp ? tmp : out, "w")));
|
||||
LoadRelationships(argc, argv);
|
||||
Crunch();
|
||||
size_t bitmaplen = roundup((sources.i + 8) / 8, 4);
|
||||
visited = malloc(bitmaplen);
|
||||
for (size_t i = 0; i < sources.i; ++i) {
|
||||
const char *path = &strings.p[sources.p[i].name];
|
||||
if (!IsObjectSource(path)) continue;
|
||||
bool needprefix = !startswith(path, "o/");
|
||||
const char *prefix = !needprefix ? "" : IsModeless(path) ? "o/" : buildroot;
|
||||
fprintf(fout, "\n%s%s.o: \\\n\t%s", prefix, StripExt(path), path);
|
||||
memset(visited, 0, bitmaplen);
|
||||
bts(visited, i);
|
||||
Dive(i);
|
||||
fprintf(fout, "\n");
|
||||
}
|
||||
if (fclose(fout) == -1) perror(out), exit(1);
|
||||
if (tmp) {
|
||||
if (rename(tmp, out) == -1) perror(out), exit(1);
|
||||
}
|
||||
free_s(&strings.p);
|
||||
free_s(&sources.p);
|
||||
free_s(&edges.p);
|
||||
free_s(&visited);
|
||||
free_s(&tmp);
|
||||
return 0;
|
||||
}
|
665
tool/build/package.c
Normal file
665
tool/build/package.c
Normal file
|
@ -0,0 +1,665 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/alg/bisect.h"
|
||||
#include "libc/alg/bisectcarleft.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/conv/sizemultiply.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/elf/struct/rela.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/kompressor.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
#include "tool/build/lib/persist.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Build Package Script.
|
||||
*
|
||||
* FIRST PURPOSE
|
||||
*
|
||||
* This script verifies the well-formedness of dependencies, e.g.
|
||||
*
|
||||
* o/tool/build/package.com \
|
||||
* -o o/libc/stubs/stubs.pkg \
|
||||
* o/libc/stubs/{a,b,...}.o
|
||||
*
|
||||
* o/tool/build/package.com \
|
||||
* -o o/libc/nexgen32e/nexgen32e.pkg \
|
||||
* -d o/libc/stubs/stubs.pkg \
|
||||
* o/libc/nexgen32e/{a,b,...}.o
|
||||
*
|
||||
* We want the following:
|
||||
*
|
||||
* 1. FOO declares in FOO_DIRECTDEPS where its undefined symbols are.
|
||||
* 2. FOO_DIRECTDEPS is complete, so FOO ∪ FOO_DIRECTDEPS has no UNDEFs.
|
||||
* 3. FOO_DIRECTDEPS is non-transitive; thus this tool is incremental.
|
||||
* 4. Package relationships on a whole are acyclic.
|
||||
*
|
||||
* These rules help keep the structure of large codebases easy to
|
||||
* understand. More importantly, it allows us to further optimize
|
||||
* compiled objects very cheaply as the build progresses.
|
||||
*
|
||||
* SECOND PURPOSE
|
||||
*
|
||||
* We want all storage to be thread-local storage. So we change
|
||||
* RIP-relative instructions to be RBX-relative, only when they
|
||||
* reference sections in the binary mutable after initialization.
|
||||
*
|
||||
* This is basically what the Go language does to implement its fiber
|
||||
* multiprocessing model. We can have this in C by appropriating all the
|
||||
* work folks put into enriching GNU C with WIN32 and ASLR lool.
|
||||
*
|
||||
* THIRD PURPOSE
|
||||
*
|
||||
* Compress read-only data sections of particularly low entropy, using
|
||||
* the most appropriate directly-linked algorithm and then inject code
|
||||
* into _init() that calls it. If the data is extremely low energy, we
|
||||
* will inject code for merging page table entries too. The overcommit
|
||||
* here is limitless.
|
||||
*/
|
||||
|
||||
#define PACKAGE_MAGIC bswap_32(0xBEEFBEEFu)
|
||||
#define PACKAGE_ABI 1
|
||||
|
||||
struct Packages {
|
||||
size_t i, n;
|
||||
struct Package {
|
||||
uint32_t magic;
|
||||
int32_t abi;
|
||||
uint32_t path; /* pkg->strings.p[path] */
|
||||
int64_t fd; /* not persisted */
|
||||
void *addr; /* not persisted */
|
||||
size_t size; /* not persisted */
|
||||
struct Strings {
|
||||
size_t i, n;
|
||||
char *p; /* persisted as pkg+RVA */
|
||||
} strings; /* TODO(jart): interning? */
|
||||
struct Objects {
|
||||
size_t i, n;
|
||||
struct Object {
|
||||
uint32_t path; /* pkg->strings.p[path] */
|
||||
int64_t fd; /* not persisted */
|
||||
struct Elf64_Ehdr *elf; /* not persisted */
|
||||
size_t size; /* not persisted */
|
||||
char *strs; /* not persisted */
|
||||
Elf64_Sym *syms; /* not persisted */
|
||||
Elf64_Xword symcount; /* not persisted */
|
||||
struct Sections {
|
||||
size_t i, n;
|
||||
struct Section {
|
||||
enum SectionKind {
|
||||
kUndef,
|
||||
kText,
|
||||
kData,
|
||||
kPiroRelo,
|
||||
kPiroData,
|
||||
kPiroBss,
|
||||
kBss,
|
||||
} kind;
|
||||
struct Ops {
|
||||
size_t i, n;
|
||||
struct Op {
|
||||
int32_t offset;
|
||||
uint8_t decoded_length;
|
||||
uint8_t pos_disp;
|
||||
uint16_t __pad;
|
||||
} * p;
|
||||
} ops;
|
||||
} * p;
|
||||
} sections; /* not persisted */
|
||||
} * p; /* persisted as pkg+RVA */
|
||||
} objects;
|
||||
struct Symbols {
|
||||
size_t i, n;
|
||||
struct Symbol {
|
||||
uint32_t name; /* pkg->strings.p[name] */
|
||||
enum SectionKind kind : 8;
|
||||
uint8_t bind : 4;
|
||||
uint8_t type : 4;
|
||||
uint16_t object; /* pkg->objects.p[object] */
|
||||
} * p; /* persisted as pkg+RVA */
|
||||
} symbols, undefs; /* TODO(jart): hash undefs? */
|
||||
} * *p; /* persisted across multiple files */
|
||||
};
|
||||
|
||||
int CompareSymbolName(const struct Symbol *a, const struct Symbol *b,
|
||||
const char *strs[hasatleast 2]) {
|
||||
return strcmp(&strs[0][a->name], &strs[1][b->name]);
|
||||
}
|
||||
|
||||
struct Package *LoadPackage(const char *path) {
|
||||
int fd;
|
||||
ssize_t i;
|
||||
struct stat st;
|
||||
struct Package *pkg;
|
||||
CHECK(fileexists(path), "%s: %s: %s\n", "error", path, "not found");
|
||||
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_NE(MAP_FAILED, (pkg = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, fd, 0)));
|
||||
CHECK_NE(-1, close(fd));
|
||||
CHECK_EQ(PACKAGE_MAGIC, pkg->magic, "corrupt package: %`'s", path);
|
||||
pkg->strings.p = (char *)((intptr_t)pkg->strings.p + (intptr_t)pkg);
|
||||
pkg->objects.p = (struct Object *)((intptr_t)pkg->objects.p + (intptr_t)pkg);
|
||||
pkg->symbols.p = (struct Symbol *)((intptr_t)pkg->symbols.p + (intptr_t)pkg);
|
||||
CHECK(strcmp(path, &pkg->strings.p[pkg->path]) == 0,
|
||||
"corrupt package: %`'s pkg=%p strings=%p", path, pkg, pkg->strings.p);
|
||||
pkg->addr = pkg;
|
||||
pkg->size = st.st_size;
|
||||
return pkg;
|
||||
}
|
||||
|
||||
void AddDependency(struct Packages *deps, const char *path) {
|
||||
struct Package *pkg;
|
||||
pkg = LoadPackage(path);
|
||||
CHECK_NE(-1, append(deps, &pkg));
|
||||
}
|
||||
|
||||
void WritePackage(struct Package *pkg) {
|
||||
CHECK_NE(0, PACKAGE_MAGIC);
|
||||
pkg->magic = PACKAGE_MAGIC;
|
||||
pkg->abi = PACKAGE_ABI;
|
||||
DEBUGF("%s has %,ld objects, %,ld symbols, and a %,ld byte string table",
|
||||
&pkg->strings.p[pkg->path], pkg->objects.i, pkg->symbols.i,
|
||||
pkg->strings.i);
|
||||
PersistObject(
|
||||
&pkg->strings.p[pkg->path], 64,
|
||||
&(struct ObjectParam){
|
||||
sizeof(struct Package),
|
||||
pkg,
|
||||
&pkg->magic,
|
||||
&pkg->abi,
|
||||
(struct ObjectArrayParam[]){
|
||||
{pkg->strings.i, sizeof(pkg->strings.p[0]), &pkg->strings.p},
|
||||
{pkg->objects.i, sizeof(pkg->objects.p[0]), &pkg->objects.p},
|
||||
{pkg->symbols.i, sizeof(pkg->symbols.p[0]), &pkg->symbols.p},
|
||||
{0},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
|
||||
char *argv[]) {
|
||||
long i, si, opt;
|
||||
pkg->path = -1;
|
||||
while ((opt = getopt(argc, argv, "vho:d:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
g_loglevel = kLogDebug;
|
||||
break;
|
||||
case 'o':
|
||||
pkg->path = concat(&pkg->strings, optarg, strlen(optarg) + 1);
|
||||
break;
|
||||
case 'd':
|
||||
AddDependency(deps, optarg);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: %s [%s %s] [%s %s] %s\n", "Usage",
|
||||
program_invocation_name, "-o", "OUTPACKAGE", "-d", "DEPPACKAGE",
|
||||
"OBJECT...");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
CHECK_NE(-1, pkg->path);
|
||||
CHECK_LT(optind, argc,
|
||||
"no objects passed to package.com; "
|
||||
"is your foo.mk $(FOO_OBJS) glob broken?");
|
||||
for (i = optind; i < argc; ++i) {
|
||||
CHECK_NE(-1, (si = concat(&pkg->strings, argv[i], strlen(argv[i]) + 1)));
|
||||
CHECK_NE(-1, append(&pkg->objects, (&(struct Object){si})));
|
||||
}
|
||||
}
|
||||
|
||||
void IndexSections(struct Object *obj) {
|
||||
size_t i;
|
||||
struct Op op;
|
||||
const char *name;
|
||||
const uint8_t *code;
|
||||
struct Section sect;
|
||||
const Elf64_Shdr *shdr;
|
||||
struct XedDecodedInst xedd;
|
||||
for (i = 0; i < obj->elf->e_shnum; ++i) {
|
||||
memset(§, 0, sizeof(sect));
|
||||
CHECK_NOTNULL((shdr = getelfsectionheaderaddress(obj->elf, obj->size, i)));
|
||||
if (shdr->sh_type != SHT_NULL) {
|
||||
CHECK_NOTNULL((name = getelfsectionname(obj->elf, obj->size, shdr)));
|
||||
if (startswith(name, ".sort.")) name += 5;
|
||||
if ((strcmp(name, ".piro.relo") == 0 ||
|
||||
startswith(name, ".piro.relo.")) ||
|
||||
(strcmp(name, ".data.rel.ro") == 0 ||
|
||||
startswith(name, ".data.rel.ro."))) {
|
||||
sect.kind = kPiroRelo;
|
||||
} else if (strcmp(name, ".piro.data") == 0 ||
|
||||
startswith(name, ".piro.data.")) {
|
||||
sect.kind = kPiroData;
|
||||
} else if (strcmp(name, ".piro.bss") == 0 ||
|
||||
startswith(name, ".piro.bss.")) {
|
||||
sect.kind = kPiroBss;
|
||||
} else if (strcmp(name, ".data") == 0 || startswith(name, ".data.")) {
|
||||
sect.kind = kData;
|
||||
} else if (strcmp(name, ".bss") == 0 || startswith(name, ".bss.")) {
|
||||
sect.kind = kBss;
|
||||
} else {
|
||||
sect.kind = kText;
|
||||
}
|
||||
} else {
|
||||
sect.kind = kUndef; /* should always and only be section #0 */
|
||||
}
|
||||
if (shdr->sh_flags & SHF_EXECINSTR) {
|
||||
CHECK_NOTNULL((code = getelfsectionaddress(obj->elf, obj->size, shdr)));
|
||||
for (op.offset = 0; op.offset < shdr->sh_size;
|
||||
op.offset += op.decoded_length) {
|
||||
if (xed_instruction_length_decode(
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64),
|
||||
&code[op.offset],
|
||||
min(shdr->sh_size - op.offset, XED_MAX_INSTRUCTION_BYTES)) ==
|
||||
XED_ERROR_NONE) {
|
||||
op.decoded_length = xedd.decoded_length;
|
||||
op.pos_disp = xedd.operands.pos_disp;
|
||||
} else {
|
||||
op.decoded_length = 1;
|
||||
op.pos_disp = 0;
|
||||
}
|
||||
CHECK_NE(-1, append(§.ops, &op));
|
||||
}
|
||||
}
|
||||
CHECK_NE(-1, append(&obj->sections, §));
|
||||
}
|
||||
}
|
||||
|
||||
enum SectionKind ClassifySection(struct Object *obj, uint8_t type,
|
||||
Elf64_Section shndx) {
|
||||
if (type == STT_COMMON) return kBss;
|
||||
if (!obj->sections.i) return kText;
|
||||
return obj->sections.p[min(max(0, shndx), obj->sections.i - 1)].kind;
|
||||
}
|
||||
|
||||
void LoadSymbols(struct Package *pkg, uint32_t object) {
|
||||
Elf64_Xword i;
|
||||
const char *name;
|
||||
struct Object *obj;
|
||||
struct Symbol symbol;
|
||||
obj = &pkg->objects.p[object];
|
||||
symbol.object = object;
|
||||
for (i = 0; i < obj->symcount; ++i) {
|
||||
symbol.bind = ELF64_ST_BIND(obj->syms[i].st_info);
|
||||
symbol.type = ELF64_ST_TYPE(obj->syms[i].st_info);
|
||||
if (symbol.bind != STB_LOCAL &&
|
||||
(symbol.type == STT_OBJECT || symbol.type == STT_FUNC ||
|
||||
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE)) {
|
||||
name = getelfstring(obj->elf, obj->size, obj->strs, obj->syms[i].st_name);
|
||||
DEBUGF("%s", name);
|
||||
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") != 0) {
|
||||
symbol.kind = ClassifySection(obj, symbol.type, obj->syms[i].st_shndx);
|
||||
CHECK_NE(-1,
|
||||
(symbol.name = concat(&pkg->strings, name, strlen(name) + 1)));
|
||||
CHECK_NE(-1,
|
||||
append(symbol.kind != kUndef ? &pkg->symbols : &pkg->undefs,
|
||||
&symbol));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot,
|
||||
int flags) {
|
||||
int fd;
|
||||
struct stat st;
|
||||
CHECK_NE(-1, (fd = open(&pkg->strings.p[obj->path], mode)), "path=%`'s",
|
||||
&pkg->strings.p[obj->path]);
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_NE(MAP_FAILED, (obj->elf = mmap(NULL, (obj->size = st.st_size), prot,
|
||||
flags, fd, 0)));
|
||||
CHECK_NE(-1, close(fd));
|
||||
CHECK(iself64binary(obj->elf, obj->size));
|
||||
CHECK_NOTNULL((obj->strs = getelfstringtable(obj->elf, obj->size)));
|
||||
CHECK_NOTNULL(
|
||||
(obj->syms = getelfsymboltable(obj->elf, obj->size, &obj->symcount)));
|
||||
CHECK_NE(0, obj->symcount);
|
||||
IndexSections(obj);
|
||||
}
|
||||
|
||||
void CloseObject(struct Object *obj) {
|
||||
CHECK_NE(-1, munmap(obj->elf, obj->size));
|
||||
}
|
||||
|
||||
void LoadObjects(struct Package *pkg) {
|
||||
size_t i;
|
||||
struct Object *obj;
|
||||
for (i = 0; i < pkg->objects.i; ++i) {
|
||||
obj = &pkg->objects.p[i];
|
||||
OpenObject(pkg, obj, O_RDONLY, PROT_READ, MAP_SHARED);
|
||||
LoadSymbols(pkg, i);
|
||||
CloseObject(obj);
|
||||
}
|
||||
qsort_r(&pkg->symbols.p[0], pkg->symbols.i, sizeof(pkg->symbols.p[0]),
|
||||
(void *)CompareSymbolName,
|
||||
(const char *[2]){pkg->strings.p, pkg->strings.p});
|
||||
}
|
||||
|
||||
bool FindSymbol(const char *name, struct Package *pkg,
|
||||
struct Packages *directdeps, struct Package **out_pkg,
|
||||
struct Symbol **out_sym) {
|
||||
size_t i;
|
||||
struct Package *dep;
|
||||
struct Symbol key, *sym;
|
||||
key.name = 0;
|
||||
if ((sym = bisect(&key, &pkg->symbols.p[0], pkg->symbols.i,
|
||||
sizeof(pkg->symbols.p[0]), (void *)CompareSymbolName,
|
||||
(const char *[2]){name, pkg->strings.p}))) {
|
||||
if (out_pkg) *out_pkg = pkg;
|
||||
if (out_sym) *out_sym = sym;
|
||||
return true;
|
||||
}
|
||||
for (i = 0; i < directdeps->i; ++i) {
|
||||
dep = directdeps->p[i];
|
||||
if ((sym = bisect(&key, &dep->symbols.p[0], dep->symbols.i,
|
||||
sizeof(dep->symbols.p[0]), (void *)CompareSymbolName,
|
||||
(const char *[2]){name, dep->strings.p}))) {
|
||||
if (out_pkg) *out_pkg = dep;
|
||||
if (out_sym) *out_sym = sym;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
|
||||
size_t i, j;
|
||||
struct Package *dep;
|
||||
struct Symbol *undef;
|
||||
for (i = 0; i < pkg->undefs.i; ++i) {
|
||||
undef = &pkg->undefs.p[i];
|
||||
if (undef->bind == STB_WEAK) continue;
|
||||
if (!FindSymbol(&pkg->strings.p[undef->name], pkg, deps, NULL, NULL)) {
|
||||
fprintf(stderr, "%s: %s (%s) %s %s\n", "error",
|
||||
&pkg->strings.p[undef->name],
|
||||
&pkg->strings.p[pkg->objects.p[undef->object].path],
|
||||
"not defined by direct deps of", &pkg->strings.p[pkg->path]);
|
||||
for (j = 0; j < deps->i; ++j) {
|
||||
dep = deps->p[j];
|
||||
fputc('\t', stderr);
|
||||
fputs(&dep->strings.p[dep->path], stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
free(pkg->undefs.p);
|
||||
memset(&pkg->undefs, 0, sizeof(pkg->undefs));
|
||||
}
|
||||
|
||||
forceinline bool IsRipRelativeModrm(uint8_t modrm) {
|
||||
return (modrm & 0b11000111) == 0b00000101;
|
||||
}
|
||||
|
||||
forceinline uint8_t ChangeRipToRbx(uint8_t modrm) {
|
||||
return (modrm & 0b00111000) | 0b10000011;
|
||||
}
|
||||
|
||||
void OptimizeRelocations(struct Package *pkg, struct Packages *deps,
|
||||
struct Object *obj) {
|
||||
Elf64_Half i;
|
||||
struct Op *op;
|
||||
Elf64_Rela *rela;
|
||||
struct Symbol *refsym;
|
||||
struct Package *refpkg;
|
||||
unsigned char *code, *p;
|
||||
Elf64_Shdr *shdr, *shdrcode;
|
||||
for (i = 0; i < obj->elf->e_shnum; ++i) {
|
||||
shdr = getelfsectionheaderaddress(obj->elf, obj->size, i);
|
||||
if (shdr->sh_type == SHT_RELA) {
|
||||
CHECK_EQ(sizeof(struct Elf64_Rela), shdr->sh_entsize);
|
||||
CHECK_NOTNULL((shdrcode = getelfsectionheaderaddress(obj->elf, obj->size,
|
||||
shdr->sh_info)));
|
||||
if (!(shdrcode->sh_flags & SHF_EXECINSTR)) continue;
|
||||
CHECK_NOTNULL(
|
||||
(code = getelfsectionaddress(obj->elf, obj->size, shdrcode)));
|
||||
for (rela = getelfsectionaddress(obj->elf, obj->size, shdr);
|
||||
((uintptr_t)rela + shdr->sh_entsize <=
|
||||
min((uintptr_t)obj->elf + obj->size,
|
||||
(uintptr_t)obj->elf + shdr->sh_offset + shdr->sh_size));
|
||||
++rela) {
|
||||
CHECK_LT(ELF64_R_SYM(rela->r_info), obj->symcount);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Change (%rip) to (%rbx) on program instructions that
|
||||
* reference memory, if and only if the memory location is a
|
||||
* global variable that's mutable after initialization. The
|
||||
* displacement is also updated to be relative to the image
|
||||
* base, rather than relative to the program counter.
|
||||
*/
|
||||
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
|
||||
ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCREL) &&
|
||||
FindSymbol(
|
||||
getelfstring(obj->elf, obj->size, obj->strs,
|
||||
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
||||
pkg, deps, &refpkg, &refsym) &&
|
||||
(refsym->kind == kData || refsym->kind == kBss) &&
|
||||
IsRipRelativeModrm(code[rela->r_offset - 1])) {
|
||||
op = &obj->sections.p[shdr->sh_info].ops.p[bisectcarleft(
|
||||
(const int32_t(*)[2])obj->sections.p[shdr->sh_info].ops.p,
|
||||
obj->sections.p[shdr->sh_info].ops.i, rela->r_offset)];
|
||||
CHECK_GT(op->decoded_length, 4);
|
||||
CHECK_GT(op->pos_disp, 0);
|
||||
rela->r_info = ELF64_R_INFO(ELF64_R_SYM(rela->r_info), R_X86_64_32S);
|
||||
rela->r_addend = -IMAGE_BASE_VIRTUAL + rela->r_addend +
|
||||
(op->decoded_length - op->pos_disp);
|
||||
code[rela->r_offset - 1] = ChangeRipToRbx(code[rela->r_offset - 1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GCC isn't capable of -mnop-mcount when using -fpie.
|
||||
* Let's fix that. It saves ~14 cycles per function call.
|
||||
* Then libc/runtime/ftrace.greg.c morphs it back at runtime.
|
||||
*/
|
||||
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX &&
|
||||
strcmp(getelfstring(obj->elf, obj->size, obj->strs,
|
||||
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
||||
"mcount") == 0) {
|
||||
rela->r_info = R_X86_64_NONE;
|
||||
p = &code[rela->r_offset - 2];
|
||||
p[0] = 0x66; /* nopw 0x00(%rax,%rax,1) */
|
||||
p[1] = 0x0f;
|
||||
p[2] = 0x1f;
|
||||
p[3] = 0x44;
|
||||
p[4] = 0x00;
|
||||
p[5] = 0x00;
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's just try to nop mcount calls in general due to the above.
|
||||
*/
|
||||
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
|
||||
ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) &&
|
||||
strcmp(getelfstring(obj->elf, obj->size, obj->strs,
|
||||
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
||||
"mcount") == 0) {
|
||||
rela->r_info = R_X86_64_NONE;
|
||||
p = &code[rela->r_offset - 1];
|
||||
p[0] = 0x0f; /* nopl 0x00(%rax,%rax,1) */
|
||||
p[1] = 0x1f;
|
||||
p[2] = 0x44;
|
||||
p[3] = 0x00;
|
||||
p[4] = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsSymbolDirectlyReachable(struct Package *pkg, struct Packages *deps,
|
||||
const char *symbol) {
|
||||
return FindSymbol(symbol, pkg, deps, NULL, NULL);
|
||||
}
|
||||
|
||||
struct RlEncoder {
|
||||
size_t i, n;
|
||||
struct RlDecode *p;
|
||||
};
|
||||
|
||||
ssize_t rlencode_extend(struct RlEncoder *rle, size_t n) {
|
||||
size_t n2;
|
||||
struct RlDecode *p2;
|
||||
n2 = rle->n;
|
||||
if (!n2) n2 = 512;
|
||||
while (n > n2) n2 += n2 >> 1;
|
||||
if (!(p2 = realloc(rle->p, n2 * sizeof(rle->p[0])))) return -1;
|
||||
rle->p = p2;
|
||||
rle->n = n2;
|
||||
return n2;
|
||||
}
|
||||
|
||||
void rlencode_encode(struct RlEncoder *rle, const unsigned char *data,
|
||||
size_t size) {
|
||||
size_t i, j;
|
||||
for (i = 0; i < size; i += j) {
|
||||
for (j = 1; j < 255 && i + j < size; ++j) {
|
||||
if (data[i] != data[i + j]) break;
|
||||
}
|
||||
rle->p[rle->i].repititions = j;
|
||||
rle->p[rle->i].byte = data[i];
|
||||
rle->i++;
|
||||
}
|
||||
rle->p[rle->i].repititions = 0;
|
||||
rle->p[rle->i].byte = 0;
|
||||
rle->i++;
|
||||
}
|
||||
|
||||
ssize_t rlencode(struct RlEncoder *rle, const unsigned char *data,
|
||||
size_t size) {
|
||||
if (size + 1 > rle->n && rlencode_extend(rle, size + 1) == -1) return -1;
|
||||
rlencode_encode(rle, data, size);
|
||||
assert(rle->i <= rle->n);
|
||||
return rle->i;
|
||||
}
|
||||
|
||||
void CompressLowEntropyReadOnlyDataSections(struct Package *pkg,
|
||||
struct Packages *deps,
|
||||
struct Object *obj) {
|
||||
Elf64_Half i;
|
||||
const char *name;
|
||||
unsigned char *p;
|
||||
Elf64_Shdr *shdr;
|
||||
struct RlEncoder rle;
|
||||
bool haverldecode, isprofitable;
|
||||
memset(&rle, 0, sizeof(rle));
|
||||
haverldecode = IsSymbolDirectlyReachable(pkg, deps, "rldecode");
|
||||
for (i = 0; i < obj->elf->e_shnum; ++i) {
|
||||
if ((shdr = getelfsectionheaderaddress(obj->elf, obj->size, i)) &&
|
||||
shdr->sh_size >= 256 &&
|
||||
(shdr->sh_type == SHT_PROGBITS &&
|
||||
!(shdr->sh_flags &
|
||||
(SHF_WRITE | SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED))) &&
|
||||
(p = getelfsectionaddress(obj->elf, obj->size, shdr)) &&
|
||||
startswith((name = getelfsectionname(obj->elf, obj->size, shdr)),
|
||||
".rodata") &&
|
||||
rlencode(&rle, p, shdr->sh_size) != -1) {
|
||||
isprofitable = rle.i * sizeof(rle.p[0]) <= shdr->sh_size / 2;
|
||||
LOGF("%s(%s): rlencode()%s on %s is%s profitable (%,zu → %,zu bytes)",
|
||||
&pkg->strings.p[pkg->path], &pkg->strings.p[obj->path],
|
||||
haverldecode ? "" : " [NOT LINKED]", name,
|
||||
isprofitable ? "" : " NOT", shdr->sh_size, rle.i * sizeof(rle.p[0]));
|
||||
}
|
||||
}
|
||||
free(rle.p);
|
||||
}
|
||||
|
||||
void RewriteObjects(struct Package *pkg, struct Packages *deps) {
|
||||
size_t i;
|
||||
struct Object *obj;
|
||||
#if 0
|
||||
struct ElfWriter *elf;
|
||||
elf = elfwriter_open(gc(xstrcat(&pkg->strings.p[pkg->path], ".o")), 0644);
|
||||
elfwriter_cargoculting(elf);
|
||||
#endif
|
||||
for (i = 0; i < pkg->objects.i; ++i) {
|
||||
obj = &pkg->objects.p[i];
|
||||
OpenObject(pkg, obj, O_RDWR, PROT_READ | PROT_WRITE, MAP_SHARED);
|
||||
OptimizeRelocations(pkg, deps, obj);
|
||||
#if 0
|
||||
CompressLowEntropyReadOnlyDataSections(pkg, deps, obj);
|
||||
#endif
|
||||
CloseObject(obj);
|
||||
}
|
||||
#if 0
|
||||
elfwriter_close(elf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Package(int argc, char *argv[], struct Package *pkg,
|
||||
struct Packages *deps) {
|
||||
size_t i, j;
|
||||
GetOpts(pkg, deps, argc, argv);
|
||||
LoadObjects(pkg);
|
||||
CheckStrictDeps(pkg, deps);
|
||||
RewriteObjects(pkg, deps);
|
||||
WritePackage(pkg);
|
||||
for (i = 0; i < deps->i; ++i) {
|
||||
CHECK_NE(-1, munmap(deps->p[i]->addr, deps->p[i]->size));
|
||||
}
|
||||
for (i = 0; i < pkg->objects.i; ++i) {
|
||||
for (j = 0; j < pkg->objects.p[i].sections.i; ++j) {
|
||||
free(pkg->objects.p[i].sections.p[j].ops.p);
|
||||
}
|
||||
free(pkg->objects.p[i].sections.p);
|
||||
}
|
||||
free_s(&pkg->strings.p);
|
||||
free_s(&pkg->objects.p);
|
||||
free_s(&pkg->symbols.p);
|
||||
free_s(&deps->p);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct Package pkg;
|
||||
struct Packages deps;
|
||||
memset(&pkg, 0, sizeof(pkg));
|
||||
memset(&deps, 0, sizeof(deps));
|
||||
Package(argc, argv, &pkg, &deps);
|
||||
return 0;
|
||||
}
|
126
tool/build/refactor.c
Normal file
126
tool/build/refactor.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/dt.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Pretty fast substring refactor tool.
|
||||
*/
|
||||
|
||||
static const char kBefore[] = "\
|
||||
│ Copyright 2019 Justine Alexandra Roberts Tunney │\n\
|
||||
│ │\n\
|
||||
│ Copying of this file is authorized only if (1) you are Justine Tunney, or │\n\
|
||||
│ (2) you make absolutely no changes to your copy. │\n\
|
||||
│ │\n\
|
||||
│ THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES │\n\
|
||||
│ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF │\n\
|
||||
│ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR │\n\
|
||||
│ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES │\n\
|
||||
│ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN │\n\
|
||||
│ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF │\n\
|
||||
│ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. │\n\
|
||||
";
|
||||
|
||||
const char kAfter[] = "\
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │\n\
|
||||
│ │\n\
|
||||
│ This program is free software; you can redistribute it and/or modify │\n\
|
||||
│ it under the terms of the GNU General Public License as published by │\n\
|
||||
│ the Free Software Foundation; version 2 of the License. │\n\
|
||||
│ │\n\
|
||||
│ This program is distributed in the hope that it will be useful, but │\n\
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │\n\
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │\n\
|
||||
│ General Public License for more details. │\n\
|
||||
│ │\n\
|
||||
│ You should have received a copy of the GNU General Public License │\n\
|
||||
│ along with this program; if not, write to the Free Software │\n\
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │\n\
|
||||
│ 02110-1301 USA │\n\
|
||||
";
|
||||
|
||||
void RefactorFile(const char *path) {
|
||||
int fd;
|
||||
struct stat st;
|
||||
size_t len, partlen, len1, len2;
|
||||
char *mem, *spot = NULL, *part1, *part2;
|
||||
CHECK_NE(-1, (fd = open(path, O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
if ((len = st.st_size)) {
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(mem = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||
partlen = sizeof(kBefore) - 1;
|
||||
if ((spot = memmem(mem, len, kBefore, partlen))) {
|
||||
part1 = gc(xmalloc((len1 = spot - mem)));
|
||||
part2 = gc(xmalloc((len2 = len - partlen - (spot - mem))));
|
||||
memcpy(part1, mem, len1);
|
||||
memcpy(part2, spot + partlen, len2);
|
||||
}
|
||||
CHECK_NE(-1, munmap(mem, len));
|
||||
}
|
||||
CHECK_NE(-1, close(fd));
|
||||
if (spot) {
|
||||
fprintf(stderr, "found! %s\n", path);
|
||||
CHECK_NE(-1, (fd = open(path, O_RDWR | O_TRUNC)));
|
||||
CHECK_EQ(len1, write(fd, part1, len1));
|
||||
CHECK_EQ(sizeof(kAfter) - 1, write(fd, kAfter, sizeof(kAfter) - 1));
|
||||
CHECK_EQ(len2, write(fd, part2, len2));
|
||||
CHECK_NE(-1, close(fd));
|
||||
}
|
||||
}
|
||||
|
||||
void RefactorDir(const char *dpath) {
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
char *path = gc(xmalloc(PATH_MAX));
|
||||
CHECK_NOTNULL(dir = opendir(firstnonnull(dpath, ".")));
|
||||
while ((ent = readdir(dir))) {
|
||||
if (startswith(ent->d_name, ".")) continue;
|
||||
if (strcmp(ent->d_name, "o") == 0) continue;
|
||||
snprintf(path, PATH_MAX, "%s%s%s", dpath ? dpath : "", dpath ? "/" : "",
|
||||
ent->d_name);
|
||||
if (isdirectory(path)) {
|
||||
RefactorDir(path);
|
||||
} else if (isregularfile(path)) {
|
||||
RefactorFile(path);
|
||||
}
|
||||
}
|
||||
CHECK_NE(-1, closedir(dir));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
RefactorDir(NULL);
|
||||
return 0;
|
||||
}
|
243
tool/build/rle.c
Normal file
243
tool/build/rle.c
Normal file
|
@ -0,0 +1,243 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define USAGE1 \
|
||||
"NAME\n\
|
||||
\n\
|
||||
rle - Run Length Encoder\n\
|
||||
\n\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
"
|
||||
|
||||
#define USAGE2 \
|
||||
" [FLAGS] [FILE...]\n\
|
||||
\n\
|
||||
DESCRIPTION\n\
|
||||
\n\
|
||||
This is a primitive compression algorithm. Its advantage is that\n\
|
||||
the concomitant rldecode() library is seventeen bytes, and works\n\
|
||||
on IA-16, IA-32, and NexGen32e without needing to be recompiled.\n\
|
||||
\n\
|
||||
This CLI is consistent with gzip, bzip2, lzma, etc.\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-1 .. -9 ignored\n\
|
||||
-a ignored\n\
|
||||
-c send to stdout\n\
|
||||
-d decompress\n\
|
||||
-f ignored\n\
|
||||
-t test integrity\n\
|
||||
-S SUFFIX overrides .rle extension\n\
|
||||
-h shows this information\n"
|
||||
|
||||
FILE *fin_, *fout_;
|
||||
bool decompress_, test_;
|
||||
const char *suffix_, *hint_;
|
||||
|
||||
void StartErrorMessage(void) {
|
||||
fputs("error: ", stderr);
|
||||
fputs(hint_, stderr);
|
||||
fputs(": ", stderr);
|
||||
}
|
||||
|
||||
void PrintIoErrorMessage(void) {
|
||||
int err;
|
||||
err = errno;
|
||||
StartErrorMessage();
|
||||
fputs(strerror(err), stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
void PrintUsage(int rc, FILE *f) {
|
||||
fputs(USAGE1, f);
|
||||
fputs(program_invocation_name, f);
|
||||
fputs(USAGE2, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
fin_ = stdin;
|
||||
suffix_ = ".rle";
|
||||
while ((opt = getopt(argc, argv, "123456789S:acdfho:t")) != -1) {
|
||||
switch (opt) {
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 'a':
|
||||
case 'f':
|
||||
break;
|
||||
case 'c':
|
||||
fout_ = stdout;
|
||||
break;
|
||||
case 'd':
|
||||
decompress_ = true;
|
||||
break;
|
||||
case 't':
|
||||
test_ = true;
|
||||
break;
|
||||
case 'o':
|
||||
fclose_s(&fout_);
|
||||
if (!(fout_ = fopen((hint_ = optarg), "w"))) {
|
||||
PrintIoErrorMessage();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
suffix_ = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RunLengthEncode1(void) {
|
||||
int byte1, byte2, runlength;
|
||||
byte2 = -1;
|
||||
runlength = 0;
|
||||
if ((byte1 = fgetc(fin_)) == -1) return -1;
|
||||
do {
|
||||
while (++runlength < 255) {
|
||||
if ((byte2 = fgetc(fin_)) != byte1) break;
|
||||
}
|
||||
if (fputc(runlength, fout_) == -1 || fputc(byte1, fout_) == -1) {
|
||||
return -1;
|
||||
}
|
||||
runlength = 0;
|
||||
} while ((byte1 = byte2) != -1);
|
||||
return feof(fin_) ? 0 : -1;
|
||||
}
|
||||
|
||||
int RunLengthEncode2(void) { return fputc(0, fout_) | fputc(0, fout_); }
|
||||
|
||||
int EmitRun(unsigned char count, unsigned char byte) {
|
||||
do {
|
||||
if (fputc(byte, fout_) == -1) return -1;
|
||||
} while (--count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RunLengthDecode(void) {
|
||||
int byte1, byte2;
|
||||
if ((byte1 = fgetc(fin_)) == -1) return einval();
|
||||
if ((byte2 = fgetc(fin_)) == -1) return einval();
|
||||
while (byte1) {
|
||||
if (!test_ && EmitRun(byte1, byte2) == -1) return -1;
|
||||
if ((byte1 = fgetc(fin_)) == -1) break;
|
||||
if ((byte2 = fgetc(fin_)) == -1) return einval();
|
||||
}
|
||||
if (byte1 != 0 || byte2 != 0) return einval();
|
||||
fgetc(fin_);
|
||||
return feof(fin_) ? 0 : -1;
|
||||
}
|
||||
|
||||
int RunLengthCode(void) {
|
||||
if (test_ || decompress_) {
|
||||
return RunLengthDecode();
|
||||
} else {
|
||||
return RunLengthEncode1();
|
||||
}
|
||||
}
|
||||
|
||||
int Run(char **paths, size_t count) {
|
||||
int rc;
|
||||
char *p;
|
||||
size_t i, suffixlen;
|
||||
const char pathbuf[PATH_MAX];
|
||||
if (!count) {
|
||||
hint_ = "/dev/stdin";
|
||||
if (!fout_) fout_ = stdout;
|
||||
rc = RunLengthCode();
|
||||
rc |= fclose_s(&fin_);
|
||||
} else {
|
||||
rc = fclose_s(&fin_);
|
||||
for (i = 0; i < count && rc != -1; ++i) {
|
||||
rc = -1;
|
||||
if ((fin_ = fopen((hint_ = paths[i]), "r"))) {
|
||||
if (test_ || fout_) {
|
||||
rc = RunLengthCode();
|
||||
} else {
|
||||
suffixlen = strlen(suffix_);
|
||||
if (!IsTrustworthy() && strlen(paths[i]) + suffixlen + 1 > PATH_MAX) {
|
||||
return eoverflow();
|
||||
}
|
||||
p = stpcpy(pathbuf, paths[i]);
|
||||
if (!decompress_) {
|
||||
strcpy(p, suffix_);
|
||||
} else if (p - pathbuf > suffixlen &&
|
||||
memcmp(p - suffixlen, suffix_, suffixlen) == 0) {
|
||||
p[-suffixlen] = '\0';
|
||||
} else {
|
||||
return enotsup();
|
||||
}
|
||||
if ((fout_ = fopen((hint_ = pathbuf), "w"))) {
|
||||
rc = RunLengthCode();
|
||||
if (rc != -1 && !decompress_) {
|
||||
rc = RunLengthEncode2();
|
||||
}
|
||||
if ((rc |= fclose_s(&fout_)) != -1) {
|
||||
unlink(paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
rc |= fclose_s(&fin_);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rc != -1 && fout_) {
|
||||
rc = RunLengthEncode2();
|
||||
rc |= fclose_s(&fout_);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GetOpts(argc, argv);
|
||||
if (Run(argv + optind, argc - optind) != -1) {
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
PrintIoErrorMessage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
400
tool/build/runit.c
Normal file
400
tool/build/runit.c
Normal file
|
@ -0,0 +1,400 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/spawn.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/ipclassify.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ai.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/runit.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Remote test runner.
|
||||
*
|
||||
* This is able to upload and run test binaries on remote operating
|
||||
* systems with about 30 milliseconds of latency. It requires zero ops
|
||||
* work too, since it deploys the ephemeral runit daemon via SSH upon
|
||||
* ECONNREFUSED. That takes 10x longer (300 milliseconds). Further note
|
||||
* there's no make -j race conditions here, thanks to SO_REUSEPORT.
|
||||
*
|
||||
* o/default/tool/build/runit.com \
|
||||
* o/default/tool/build/runitd.com \
|
||||
* o/default/test/libc/alg/qsort_test.com \
|
||||
* freebsd.test.:31337:22
|
||||
*
|
||||
* The only thing that needs to be configured is /etc/hosts or Bind, to
|
||||
* assign numbers to the officially reserved canned names. For example:
|
||||
*
|
||||
* 192.168.0.10 windows.test. windows
|
||||
* 192.168.0.11 freebsd.test. freebsd
|
||||
* 192.168.0.12 openbsd.test. openbsd
|
||||
*
|
||||
* Life is easiest if SSH public key authentication is configured too.
|
||||
* It can be tuned as follows in ~/.ssh/config:
|
||||
*
|
||||
* host windows.test.
|
||||
* user testacct
|
||||
* host freebsd.test.
|
||||
* user testacct
|
||||
* host openbsd.test.
|
||||
* user testacct
|
||||
*
|
||||
* Firewalls may need to be configured as well, to allow port tcp:31337
|
||||
* from the local subnet. For example:
|
||||
*
|
||||
* iptables -L -vn
|
||||
* iptables -I INPUT 1 -s 10.0.0.0/8 -p tcp --dport 31337 -j ACCEPT
|
||||
* iptables -I INPUT 1 -s 192.168.0.0/16 -p tcp --dport 31337 -j ACCEPT
|
||||
*
|
||||
* If your system administrator blocks all ICMP, you'll likely encounter
|
||||
* difficulties. Consider offering feedback to his/her manager and grand
|
||||
* manager.
|
||||
*
|
||||
* Finally note this tool isn't designed for untrustworthy environments.
|
||||
* It also isn't designed to process untrustworthy inputs.
|
||||
*/
|
||||
|
||||
static const struct addrinfo kResolvHints = {.ai_family = AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP};
|
||||
|
||||
int g_sock;
|
||||
jmp_buf g_jmpbuf;
|
||||
uint16_t g_sshport, g_runitdport;
|
||||
char *g_prog, *g_runitd, *g_ssh, g_hostname[128];
|
||||
|
||||
forceinline pureconst size_t GreatestTwoDivisor(size_t x) {
|
||||
return x & (~x + 1);
|
||||
}
|
||||
|
||||
noreturn void ShowUsage(FILE *f, int rc) {
|
||||
fprintf(f, "Usage: %s RUNITD PROGRAM HOSTNAME[:RUNITDPORT[:SSHPORT]]...\n",
|
||||
program_invocation_name);
|
||||
exit(rc);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
void CheckExists(const char *path) {
|
||||
if (!isregularfile(path)) {
|
||||
fprintf(stderr, "error: %s: not found or irregular\n", path);
|
||||
ShowUsage(stderr, EX_USAGE);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
nodiscard char *MakeDeployScript(struct addrinfo *remotenic, size_t combytes) {
|
||||
const char *ip4 = (const char *)&remotenic->ai_addr4->sin_addr;
|
||||
return xasprintf("mkdir -p o/ &&\n"
|
||||
"dd bs=%zu count=%zu of=o/runitd.$$.com 2>/dev/null &&\n"
|
||||
"exec <&- &&\n"
|
||||
"chmod +x o/runitd.$$.com &&\n"
|
||||
"o/runitd.$$.com -rdl%hhu.%hhu.%hhu.%hhu -p %hu &&\n"
|
||||
"rm -f o/runitd.$$.com\n",
|
||||
GreatestTwoDivisor(combytes),
|
||||
combytes ? combytes / GreatestTwoDivisor(combytes) : 0,
|
||||
ip4[0], ip4[1], ip4[2], ip4[3], g_runitdport);
|
||||
}
|
||||
|
||||
void Upload(int pipe, int fd, struct stat *st) {
|
||||
int64_t i;
|
||||
for (i = 0; i < st->st_size;) {
|
||||
CHECK_GT(splice(fd, &i, pipe, NULL, st->st_size - i, 0), 0);
|
||||
}
|
||||
CHECK_NE(-1, close(fd));
|
||||
}
|
||||
|
||||
void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
||||
size_t got;
|
||||
struct stat st;
|
||||
char linebuf[32];
|
||||
int sshpid, wstatus, binfd, sshfds[3];
|
||||
DEBUGF("spawning %s on %s:%hu", g_runitd, g_hostname, g_runitdport);
|
||||
CHECK_NE(-1, (binfd = open(g_runitd, O_RDONLY | O_CLOEXEC)));
|
||||
CHECK_NE(-1, fstat(binfd, &st));
|
||||
sshfds[0] = -1;
|
||||
sshfds[1] = -1;
|
||||
sshfds[2] = STDERR_FILENO;
|
||||
CHECK_NE(-1, (sshpid = spawnve(
|
||||
0, sshfds, g_ssh,
|
||||
(char *const[]){"ssh", "-C", "-p",
|
||||
gc(xasprintf("%hu", g_sshport)), g_hostname,
|
||||
gc(MakeDeployScript(ai, st.st_size)), NULL},
|
||||
environ)));
|
||||
Upload(sshfds[0], binfd, &st);
|
||||
CHECK_NE(-1, close(sshfds[0]));
|
||||
CHECK_NE(-1, (got = read(sshfds[1], linebuf, sizeof(linebuf))));
|
||||
CHECK_GT(got, 0);
|
||||
linebuf[sizeof(linebuf) - 1] = '\0';
|
||||
if (strncmp(linebuf, "ready ", 6) != 0) {
|
||||
FATALF("expected ready response but got %`'.*s", got, linebuf);
|
||||
}
|
||||
g_runitdport = (uint16_t)atoi(&linebuf[6]);
|
||||
CHECK_NE(-1, close(sshfds[1]));
|
||||
CHECK_NE(-1, waitpid(sshpid, &wstatus, 0));
|
||||
CHECK_EQ(0, WEXITSTATUS(wstatus));
|
||||
}
|
||||
|
||||
void SetDeadline(int micros) {
|
||||
setitimer(ITIMER_REAL, &(const struct itimerval){{0, 0}, {0, micros}}, NULL);
|
||||
}
|
||||
|
||||
void Connect(int attempt) {
|
||||
int rc, olderr;
|
||||
const char *ip4;
|
||||
struct addrinfo *ai;
|
||||
if ((rc = getaddrinfo(g_hostname, gc(xasprintf("%hu", g_runitdport)),
|
||||
&kResolvHints, &ai)) != 0) {
|
||||
FATALF("%s:%hu: EAI_%s %m", g_hostname, g_runitdport, eai2str(rc));
|
||||
unreachable;
|
||||
}
|
||||
if (ispublicip(ai->ai_family, &ai->ai_addr4->sin_addr)) {
|
||||
ip4 = (const char *)&ai->ai_addr4->sin_addr;
|
||||
FATALF("%s points to %hhu.%hhu.%hhu.%hhu"
|
||||
" which isn't part of a local/private/testing subnet",
|
||||
g_hostname, ip4[0], ip4[1], ip4[2], ip4[3]);
|
||||
unreachable;
|
||||
}
|
||||
CHECK_NE(-1, (g_sock = socket(ai->ai_family, ai->ai_socktype | SOCK_CLOEXEC,
|
||||
ai->ai_protocol)));
|
||||
SetDeadline(50000);
|
||||
olderr = errno;
|
||||
rc = connect(g_sock, ai->ai_addr, ai->ai_addrlen);
|
||||
SetDeadline(0);
|
||||
if (rc == -1) {
|
||||
if (!attempt &&
|
||||
(errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == EINTR)) {
|
||||
errno = olderr;
|
||||
DeployEphemeralRunItDaemonRemotelyViaSsh(ai);
|
||||
Connect(1);
|
||||
} else if (errno == EINTR) {
|
||||
fprintf(stderr, "%s(%s:%hu): %s\n", "connect", g_hostname, g_runitdport,
|
||||
"offline, icmp misconfigured, or too slow; tune make HOSTS=...");
|
||||
exit(1);
|
||||
} else {
|
||||
FATALF("%s(%s:%hu): %m", "connect", g_hostname, g_runitdport);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
||||
void SendRequest(void) {
|
||||
int fd;
|
||||
int64_t off;
|
||||
struct stat st;
|
||||
const char *name;
|
||||
unsigned char *hdr;
|
||||
size_t progsize, namesize, hdrsize;
|
||||
CHECK_NE(-1, (fd = open(g_prog, O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_LE((namesize = strlen((name = basename(g_prog)))), PATH_MAX);
|
||||
CHECK_LE((progsize = st.st_size), INT_MAX);
|
||||
CHECK_NOTNULL((hdr = gc(calloc(1, (hdrsize = 4 + 1 + 4 + 4 + namesize)))));
|
||||
hdr[0 + 0] = (unsigned char)((unsigned)RUNITD_MAGIC >> 030);
|
||||
hdr[0 + 1] = (unsigned char)((unsigned)RUNITD_MAGIC >> 020);
|
||||
hdr[0 + 2] = (unsigned char)((unsigned)RUNITD_MAGIC >> 010);
|
||||
hdr[0 + 3] = (unsigned char)((unsigned)RUNITD_MAGIC >> 000);
|
||||
hdr[4 + 0] = kRunitExecute;
|
||||
hdr[5 + 0] = (unsigned char)((unsigned)namesize >> 030);
|
||||
hdr[5 + 1] = (unsigned char)((unsigned)namesize >> 020);
|
||||
hdr[5 + 2] = (unsigned char)((unsigned)namesize >> 010);
|
||||
hdr[5 + 3] = (unsigned char)((unsigned)namesize >> 000);
|
||||
hdr[9 + 0] = (unsigned char)((unsigned)progsize >> 030);
|
||||
hdr[9 + 1] = (unsigned char)((unsigned)progsize >> 020);
|
||||
hdr[9 + 2] = (unsigned char)((unsigned)progsize >> 010);
|
||||
hdr[9 + 3] = (unsigned char)((unsigned)progsize >> 000);
|
||||
memcpy(&hdr[4 + 1 + 4 + 4], name, namesize);
|
||||
CHECK_EQ(hdrsize, write(g_sock, hdr, hdrsize));
|
||||
for (off = 0; off < progsize;) {
|
||||
CHECK_GT(sendfile(g_sock, fd, &off, progsize - off), 0);
|
||||
}
|
||||
CHECK_NE(-1, shutdown(g_sock, SHUT_WR));
|
||||
}
|
||||
|
||||
int ReadResponse(void) {
|
||||
int res;
|
||||
uint32_t size;
|
||||
ssize_t rc;
|
||||
size_t n, m;
|
||||
unsigned char *p;
|
||||
enum RunitCommand cmd;
|
||||
static unsigned char msg[512];
|
||||
res = -1;
|
||||
for (;;) {
|
||||
CHECK_NE(-1, (rc = recv(g_sock, msg, sizeof(msg), 0)));
|
||||
p = &msg[0];
|
||||
n = (size_t)rc;
|
||||
if (!n) break;
|
||||
do {
|
||||
CHECK_GE(n, 4 + 1);
|
||||
CHECK_EQ(RUNITD_MAGIC, read32be(p));
|
||||
p += 4, n -= 4;
|
||||
cmd = *p++, n--;
|
||||
switch (cmd) {
|
||||
case kRunitExit:
|
||||
CHECK_GE(n, 1);
|
||||
res = *p;
|
||||
goto drop;
|
||||
case kRunitStderr:
|
||||
CHECK_GE(n, 4);
|
||||
size = read32be(p), p += 4, n -= 4;
|
||||
while (size) {
|
||||
if (n) {
|
||||
CHECK_NE(-1, (rc = write(STDERR_FILENO, p, min(n, size))));
|
||||
CHECK_NE(0, (m = (size_t)rc));
|
||||
p += m, n -= m, size -= m;
|
||||
} else {
|
||||
CHECK_NE(-1, (rc = recv(g_sock, msg, sizeof(msg), 0)));
|
||||
p = &msg[0];
|
||||
n = (size_t)rc;
|
||||
if (!n) goto drop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
die();
|
||||
}
|
||||
} while (n);
|
||||
}
|
||||
drop:
|
||||
CHECK_NE(-1, close(g_sock));
|
||||
return res;
|
||||
}
|
||||
|
||||
int RunOnHost(char *spec) {
|
||||
char *p;
|
||||
for (p = spec; *p; ++p) {
|
||||
if (*p == ':') *p = ' ';
|
||||
}
|
||||
CHECK_GE(sscanf(spec, "%100s %hu %hu", g_hostname, &g_runitdport, &g_sshport),
|
||||
1);
|
||||
if (!strchr(g_hostname, '.')) strcat(g_hostname, ".test.");
|
||||
Connect(0);
|
||||
SendRequest();
|
||||
return ReadResponse();
|
||||
}
|
||||
|
||||
bool IsParallelBuild(void) {
|
||||
const char *makeflags;
|
||||
return (makeflags = getenv("MAKEFLAGS")) && strstr(makeflags, "-j");
|
||||
}
|
||||
|
||||
bool ShouldRunInParralel(void) {
|
||||
return !IsWindows() && IsParallelBuild();
|
||||
}
|
||||
|
||||
int RunRemoteTestsInSerial(char *hosts[], int count) {
|
||||
int i, exitcode;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if ((exitcode = RunOnHost(hosts[i]))) {
|
||||
return exitcode;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OnInterrupt(int sig) {
|
||||
static bool once;
|
||||
if (!once) {
|
||||
once = true;
|
||||
gclongjmp(g_jmpbuf, 128 + sig);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int RunRemoteTestsInParallel(char *hosts[], int count) {
|
||||
const struct sigaction onsigterm = {.sa_handler = (void *)OnInterrupt};
|
||||
struct sigaction onsigint = {.sa_handler = (void *)OnInterrupt};
|
||||
int i, rc, exitcode;
|
||||
int64_t leader, *pids;
|
||||
leader = getpid();
|
||||
pids = gc(xcalloc(count, sizeof(char *)));
|
||||
if (!(exitcode = setjmp(g_jmpbuf))) {
|
||||
sigaction(SIGINT, &onsigint, NULL);
|
||||
sigaction(SIGTERM, &onsigterm, NULL);
|
||||
for (i = 0; i < count; ++i) {
|
||||
CHECK_NE(-1, (pids[i] = fork()));
|
||||
if (!pids[i]) {
|
||||
return RunOnHost(hosts[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < count; ++i) {
|
||||
CHECK_NE(-1, waitpid(pids[i], &rc, 0));
|
||||
exitcode |= WEXITSTATUS(rc);
|
||||
}
|
||||
} else if (getpid() == leader) {
|
||||
onsigint.sa_handler = SIG_IGN;
|
||||
sigaction(SIGINT, &onsigint, NULL);
|
||||
kill(0, SIGINT);
|
||||
while (waitpid(-1, NULL, 0) > 0) donothing;
|
||||
}
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
showcrashreports();
|
||||
g_loglevel = kLogDebug;
|
||||
const struct sigaction onsigalrm = {.sa_handler = (void *)missingno};
|
||||
if (argc > 1 &&
|
||||
(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
|
||||
ShowUsage(stdout, 0);
|
||||
unreachable;
|
||||
}
|
||||
if (argc < 1 + 2) ShowUsage(stderr, EX_USAGE);
|
||||
CHECK_NOTNULL((g_ssh = commandv(firstnonnull(getenv("SSH"), "ssh"))));
|
||||
CheckExists((g_runitd = argv[1]));
|
||||
CheckExists((g_prog = argv[2]));
|
||||
if (argc == 1 + 2) return 0; /* hosts list empty */
|
||||
sigaction(SIGALRM, &onsigalrm, NULL);
|
||||
g_sshport = 22;
|
||||
g_runitdport = RUNITD_PORT;
|
||||
return (ShouldRunInParralel() ? RunRemoteTestsInParallel
|
||||
: RunRemoteTestsInSerial)(&argv[3], argc - 3);
|
||||
}
|
15
tool/build/runit.h
Normal file
15
tool/build/runit.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_RUNIT_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_RUNIT_H_
|
||||
|
||||
#define RUNITD_PORT 31337
|
||||
#define RUNITD_MAGIC 0xFEEDABEEu
|
||||
#define RUNITD_TIMEOUT_MS (1000 * 10)
|
||||
|
||||
enum RunitCommand {
|
||||
kRunitExecute,
|
||||
kRunitStdout,
|
||||
kRunitStderr,
|
||||
kRunitExit,
|
||||
};
|
||||
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_RUNIT_H_ */
|
389
tool/build/runitd.c
Normal file
389
tool/build/runitd.c
Normal file
|
@ -0,0 +1,389 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/spawn.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/inaddr.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "tool/build/runit.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Remote test runner daemon.
|
||||
* Delivers 10x latency improvement over SSH (100x if Debian defaults)
|
||||
*
|
||||
* Here's how it handles connections:
|
||||
*
|
||||
* 1. Receives atomically-written request header, comprised of:
|
||||
*
|
||||
* - 4 byte nbo magic = 0xFEEDABEEu
|
||||
* - 1 byte command = kRunitExecute
|
||||
* - 4 byte nbo name length in bytes, e.g. "test1"
|
||||
* - 4 byte nbo executable file length in bytes
|
||||
* - <name bytes> (no NUL terminator)
|
||||
* - <file bytes> (it's binary data)
|
||||
*
|
||||
* 2. Runs program, after verifying it came from the IP that spawned
|
||||
* this program via SSH. Be sure to only run this over a trusted
|
||||
* physically-wired network. To use this software on untrustworthy
|
||||
* networks, wrap it with stunnel and use your own CA.
|
||||
*
|
||||
* 3. Sends stdout/stderr fragments, potentially multiple times:
|
||||
*
|
||||
* - 4 byte nbo magic = 0xFEEDABEEu
|
||||
* - 1 byte command = kRunitStdout/Stderr
|
||||
* - 4 byte nbo byte length
|
||||
* - <chunk bytes>
|
||||
*
|
||||
* 4. Sends process exit code:
|
||||
*
|
||||
* - 4 byte nbo magic = 0xFEEDABEEu
|
||||
* - 1 byte command = kRunitExit
|
||||
* - 1 byte exit status
|
||||
*/
|
||||
|
||||
#define kLogFile "o/runitd.log"
|
||||
#define kLogMaxBytes (2 * 1000 * 1000)
|
||||
|
||||
jmp_buf g_jb;
|
||||
char *g_exepath;
|
||||
volatile bool g_childterm;
|
||||
struct sockaddr_in g_servaddr;
|
||||
unsigned char g_buf[PAGESIZE];
|
||||
bool g_daemonize, g_sendready;
|
||||
int g_timeout, g_devnullfd, g_servfd, g_clifd, g_exefd;
|
||||
|
||||
void OnInterrupt(int sig) {
|
||||
static bool once;
|
||||
if (once) abort();
|
||||
once = true;
|
||||
kill(0, sig);
|
||||
for (;;) {
|
||||
if (waitpid(-1, NULL, 0) == -1) break;
|
||||
}
|
||||
gclongjmp(g_jb, sig);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
void OnChildTerminated(int sig) {
|
||||
g_childterm = true;
|
||||
}
|
||||
|
||||
noreturn void ShowUsage(FILE *f, int rc) {
|
||||
fprintf(f, "%s: %s %s\n", "Usage", program_invocation_name,
|
||||
"[-d] [-r] [-l LISTENIP] [-p PORT] [-t TIMEOUTMS]");
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
/\
|
||||
* hi
|
||||
*/
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
g_timeout = RUNITD_TIMEOUT_MS;
|
||||
g_servaddr.sin_family = AF_INET;
|
||||
g_servaddr.sin_port = htons(RUNITD_PORT);
|
||||
g_servaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
while ((opt = getopt(argc, argv, "hdrl:p:t:w:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
g_daemonize = true;
|
||||
break;
|
||||
case 'r':
|
||||
g_sendready = true;
|
||||
break;
|
||||
case 't':
|
||||
g_timeout = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
CHECK_NE(0xFFFF, (g_servaddr.sin_port = htons(parseport(optarg))));
|
||||
break;
|
||||
case 'l':
|
||||
CHECK_EQ(1, inet_pton(AF_INET, optarg, &g_servaddr.sin_addr));
|
||||
break;
|
||||
case 'h':
|
||||
ShowUsage(stdout, EXIT_SUCCESS);
|
||||
unreachable;
|
||||
default:
|
||||
ShowUsage(stderr, EX_USAGE);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodiscard char *DescribeAddress(struct sockaddr_in *addr) {
|
||||
char ip4buf[16];
|
||||
return xasprintf("%s:%hu",
|
||||
inet_ntop(addr->sin_family, &addr->sin_addr.s_addr, ip4buf,
|
||||
sizeof(ip4buf)),
|
||||
ntohs(addr->sin_port));
|
||||
}
|
||||
|
||||
void StartTcpServer(void) {
|
||||
int yes = true;
|
||||
uint32_t asize;
|
||||
CHECK_NE(-1, (g_servfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)));
|
||||
setsockopt(g_servfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
|
||||
setsockopt(g_servfd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes));
|
||||
if (bind(g_servfd, &g_servaddr, sizeof(g_servaddr)) == -1) {
|
||||
if (g_servaddr.sin_port != 0) {
|
||||
g_servaddr.sin_port = 0;
|
||||
StartTcpServer();
|
||||
return;
|
||||
} else {
|
||||
FATALF("bind failed %m");
|
||||
}
|
||||
}
|
||||
CHECK_NE(-1, listen(g_servfd, 10));
|
||||
asize = sizeof(g_servaddr);
|
||||
CHECK_NE(-1, getsockname(g_servfd, &g_servaddr, &asize));
|
||||
if (g_sendready) {
|
||||
printf("ready %hu\n", ntohs(g_servaddr.sin_port));
|
||||
fflush(stdout);
|
||||
stdout->fd = g_devnullfd;
|
||||
}
|
||||
CHECK_NE(-1, fcntl(g_servfd, F_SETFD, FD_CLOEXEC));
|
||||
LOGF("%s:%s", "listening on tcp", gc(DescribeAddress(&g_servaddr)));
|
||||
}
|
||||
|
||||
void SendExitMessage(int sock, int rc) {
|
||||
unsigned char msg[4 + 1 + 1];
|
||||
msg[0 + 0] = (unsigned char)((unsigned)RUNITD_MAGIC >> 030);
|
||||
msg[0 + 1] = (unsigned char)((unsigned)RUNITD_MAGIC >> 020);
|
||||
msg[0 + 2] = (unsigned char)((unsigned)RUNITD_MAGIC >> 010);
|
||||
msg[0 + 3] = (unsigned char)((unsigned)RUNITD_MAGIC >> 000);
|
||||
msg[4] = kRunitExit;
|
||||
msg[5] = (unsigned char)rc;
|
||||
CHECK_EQ(sizeof(msg), send(sock, msg, sizeof(msg), 0));
|
||||
}
|
||||
|
||||
void SendOutputFragmentMessage(int sock, enum RunitCommand kind,
|
||||
unsigned char *buf, size_t size) {
|
||||
ssize_t rc;
|
||||
size_t sent;
|
||||
unsigned char msg[4 + 1 + 4];
|
||||
msg[0 + 0] = (unsigned char)((unsigned)RUNITD_MAGIC >> 030);
|
||||
msg[0 + 1] = (unsigned char)((unsigned)RUNITD_MAGIC >> 020);
|
||||
msg[0 + 2] = (unsigned char)((unsigned)RUNITD_MAGIC >> 010);
|
||||
msg[0 + 3] = (unsigned char)((unsigned)RUNITD_MAGIC >> 000);
|
||||
msg[4 + 0] = kind;
|
||||
msg[5 + 0] = (unsigned char)((unsigned)size >> 030);
|
||||
msg[5 + 1] = (unsigned char)((unsigned)size >> 020);
|
||||
msg[5 + 2] = (unsigned char)((unsigned)size >> 010);
|
||||
msg[5 + 3] = (unsigned char)((unsigned)size >> 000);
|
||||
CHECK_EQ(sizeof(msg), send(sock, msg, sizeof(msg), 0));
|
||||
while (size) {
|
||||
CHECK_NE(-1, (rc = send(sock, buf, size, 0)));
|
||||
CHECK_LE((sent = (size_t)rc), size);
|
||||
size -= sent;
|
||||
buf += sent;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleClient(void) {
|
||||
const size_t kMinMsgSize = 4 + 1 + 4 + 4;
|
||||
const size_t kMaxNameSize = 32;
|
||||
const size_t kMaxFileSize = 10 * 1024 * 1024;
|
||||
unsigned char *p;
|
||||
ssize_t got, wrote;
|
||||
struct sockaddr_in addr;
|
||||
char *addrstr, *exename;
|
||||
int wstatus, child, stdiofds[3];
|
||||
uint32_t addrsize, namesize, filesize, remaining;
|
||||
|
||||
/* read request to run program */
|
||||
addrsize = sizeof(addr);
|
||||
CHECK_NE(-1, (g_clifd = accept4(g_servfd, &addr, &addrsize, SOCK_CLOEXEC)));
|
||||
defer(close_s, &g_clifd);
|
||||
addrstr = gc(DescribeAddress(&addr));
|
||||
DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr);
|
||||
got = recv(g_clifd, (p = &g_buf[0]), sizeof(g_buf), 0);
|
||||
CHECK_GE(got, kMinMsgSize);
|
||||
CHECK_LE(got, sizeof(g_buf));
|
||||
CHECK_EQ(RUNITD_MAGIC, read32be(p));
|
||||
p += 4, got -= 4;
|
||||
CHECK_EQ(kRunitExecute, *p++);
|
||||
got--;
|
||||
namesize = read32be(p), p += 4, got -= 4;
|
||||
filesize = read32be(p), p += 4, got -= 4;
|
||||
CHECK_GE(got, namesize);
|
||||
CHECK_LE(namesize, kMaxNameSize);
|
||||
CHECK_LE(filesize, kMaxFileSize);
|
||||
exename = gc(xasprintf("%.*s", namesize, p));
|
||||
g_exepath = gc(xasprintf("o/%d.%s", getpid(), basename(exename)));
|
||||
LOGF("%s asked we run %`'s (%,u bytes @ %`'s)", addrstr, exename, filesize,
|
||||
g_exepath);
|
||||
p += namesize, got -= namesize;
|
||||
|
||||
/* write the file to disk */
|
||||
remaining = filesize;
|
||||
CHECK_NE(-1, (g_exefd = creat(g_exepath, 0700)));
|
||||
defer(unlink_s, &g_exepath);
|
||||
defer(close_s, &g_exefd);
|
||||
ftruncate(g_exefd, filesize);
|
||||
if (got) {
|
||||
CHECK_EQ(got, write(g_exefd, p, got));
|
||||
CHECK_LE(got, remaining);
|
||||
remaining -= got;
|
||||
}
|
||||
while (remaining) {
|
||||
CHECK_NE(-1, (got = recv(g_clifd, g_buf, sizeof(g_buf), 0)));
|
||||
CHECK_LE(got, remaining);
|
||||
if (!got) {
|
||||
LOGF("%s %s %,u/%,u %s", addrstr, "sent", remaining, filesize,
|
||||
"bytes before hangup");
|
||||
return;
|
||||
}
|
||||
remaining -= got;
|
||||
p = &g_buf[0];
|
||||
do {
|
||||
CHECK_GT((wrote = write(g_exefd, g_buf, got)), 0);
|
||||
CHECK_LE(wrote, got);
|
||||
} while ((got -= wrote));
|
||||
}
|
||||
/* CHECK_NE(-1, shutdown(g_clifd, SHUT_RD)); */
|
||||
CHECK_NE(-1, close_s(&g_exefd));
|
||||
|
||||
/* run program, tee'ing stderr to both log and client */
|
||||
DEBUGF("spawning %s", exename);
|
||||
g_childterm = false;
|
||||
stdiofds[0] = g_devnullfd;
|
||||
stdiofds[1] = g_devnullfd;
|
||||
stdiofds[2] = -1;
|
||||
CHECK_NE(-1, (child = spawnve(0, stdiofds, g_exepath,
|
||||
(char *const[]){g_exepath, NULL}, environ)));
|
||||
DEBUGF("communicating %s[%d]", exename, child);
|
||||
for (;;) {
|
||||
CHECK_NE(-1, (got = read(stdiofds[2], g_buf, sizeof(g_buf))));
|
||||
if (!got) {
|
||||
close_s(&stdiofds[2]);
|
||||
break;
|
||||
}
|
||||
fwrite(g_buf, got, 1, stderr);
|
||||
SendOutputFragmentMessage(g_clifd, kRunitStderr, g_buf, got);
|
||||
}
|
||||
if (!g_childterm) {
|
||||
CHECK_NE(-1, waitpid(child, &wstatus, 0));
|
||||
}
|
||||
DEBUGF("exited %s[%d] → %d", exename, child, WEXITSTATUS(wstatus));
|
||||
|
||||
/* let client know how it went */
|
||||
SendExitMessage(g_clifd, WEXITSTATUS(wstatus));
|
||||
/* CHECK_NE(-1, shutdown(g_clifd, SHUT_RDWR)); */
|
||||
CHECK_NE(-1, close(g_clifd));
|
||||
}
|
||||
|
||||
int Poll(void) {
|
||||
int i, evcount;
|
||||
struct pollfd fds[] = {{g_servfd, POLLIN}};
|
||||
TryAgain:
|
||||
evcount = poll(fds, ARRAYLEN(fds), g_timeout);
|
||||
if (evcount == -1 && errno == EINTR) goto TryAgain;
|
||||
CHECK_NE(-1, evcount);
|
||||
for (i = 0; i < evcount; ++i) {
|
||||
CHECK(fds[i].revents & POLLIN);
|
||||
HandleClient();
|
||||
}
|
||||
return evcount;
|
||||
}
|
||||
|
||||
int Serve(void) {
|
||||
int rc;
|
||||
const struct sigaction onsigint = {.sa_handler = (void *)OnInterrupt,
|
||||
.sa_flags = SA_RESETHAND};
|
||||
const struct sigaction onsigterm = {.sa_handler = (void *)OnInterrupt,
|
||||
.sa_flags = SA_RESETHAND};
|
||||
const struct sigaction onsigchld = {.sa_handler = SIG_IGN,
|
||||
.sa_flags = SA_RESETHAND | SA_RESTART};
|
||||
StartTcpServer();
|
||||
defer(close_s, &g_servfd);
|
||||
if (!(rc = setjmp(g_jb))) {
|
||||
sigaction(SIGINT, &onsigint, NULL);
|
||||
sigaction(SIGTERM, &onsigterm, NULL);
|
||||
sigaction(SIGCHLD, &onsigchld, NULL);
|
||||
while (g_servfd != -1) {
|
||||
if (!Poll()) break;
|
||||
}
|
||||
LOGF("timeout expired, shutting down");
|
||||
} else {
|
||||
if (isatty(fileno(stderr))) fputc('\r', stderr);
|
||||
LOGF("got %s, shutting down", strsignal(rc));
|
||||
rc += 128;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Daemonize(void) {
|
||||
struct stat st;
|
||||
if (fork() > 0) _exit(0);
|
||||
setsid();
|
||||
if (fork() > 0) _exit(0);
|
||||
stdin->fd = g_devnullfd;
|
||||
if (!g_sendready) stdout->fd = g_devnullfd;
|
||||
if (stat(kLogFile, &st) != -1 && st.st_size > kLogMaxBytes) unlink(kLogFile);
|
||||
freopen(kLogFile, "a", stderr);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
showcrashreports();
|
||||
g_loglevel = kLogDebug;
|
||||
GetOpts(argc, argv);
|
||||
CHECK_NE(-1, (g_devnullfd = open("/dev/null", O_RDWR)));
|
||||
defer(close_s, &g_devnullfd);
|
||||
if (!isdirectory("o")) CHECK_NE(-1, mkdir("o", 0700));
|
||||
if (g_daemonize) Daemonize();
|
||||
return Serve();
|
||||
}
|
303
tool/build/zipobj.c
Normal file
303
tool/build/zipobj.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/dos.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/zip.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
|
||||
#define ZIP_LOCALFILE_SECTION ".piro.data.sort.zip.2."
|
||||
#define ZIP_DIRECTORY_SECTION ".piro.data.sort.zip.4."
|
||||
|
||||
#define PUT8(P, V) *P++ = V
|
||||
#define PUT16(P, V) P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P += 2
|
||||
#define PUT32(P, V) \
|
||||
P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P[2] = V >> 020 & 0xff, \
|
||||
P[3] = V >> 030 & 0xff, P += 4
|
||||
|
||||
char *symbol_;
|
||||
char *outpath_;
|
||||
|
||||
const size_t kMinCompressSize = 32;
|
||||
const char kNoCompressExts[][8] = {".gz", ".xz", ".jpg", ".png",
|
||||
".gif", ".zip", ".bz2", ".mpg",
|
||||
".mp4", ".lz4", ".webp", ".mpeg"};
|
||||
|
||||
noreturn void PrintUsage(int rc, FILE *f) {
|
||||
fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name,
|
||||
" [-o FILE] [-s SYMBOL] [FILE...]\n");
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int *argc, char ***argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(*argc, *argv, "?ho:s:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
outpath_ = optarg;
|
||||
break;
|
||||
case 's':
|
||||
symbol_ = optarg;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
*argc -= optind;
|
||||
*argv += optind;
|
||||
CHECK_NOTNULL(outpath_);
|
||||
}
|
||||
|
||||
bool IsPureAscii(const void *data, size_t size) {
|
||||
const unsigned char *p, *pe;
|
||||
for (p = data, pe = p + size; p < pe; ++p) {
|
||||
if (!*p || *p >= 0x80) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShouldCompress(const char *name, size_t size) {
|
||||
size_t i;
|
||||
char key[8];
|
||||
const char *p;
|
||||
if (!(p = memrchr(name, '.', size))) return true;
|
||||
strncpy(key, p, sizeof(key));
|
||||
for (i = 0; i < ARRAYLEN(kNoCompressExts); ++i) {
|
||||
if (memcmp(key, kNoCompressExts[i], sizeof(key)) == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
|
||||
uint16_t *out_date) {
|
||||
struct tm tm;
|
||||
CHECK_NOTNULL(localtime_r(&utcunixts, &tm));
|
||||
*out_time = DOS_TIME(tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
*out_date = DOS_DATE(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
||||
}
|
||||
|
||||
static unsigned char *EmitZipLfileHdr(unsigned char *op, const void *name,
|
||||
size_t namesize, uint32_t crc,
|
||||
uint8_t era, uint16_t gflags,
|
||||
uint16_t method, uint16_t mtime,
|
||||
uint16_t mdate, size_t compsize,
|
||||
size_t uncompsize) {
|
||||
PUT32(op, kZipLfileHdrMagic);
|
||||
PUT8(op, era);
|
||||
PUT8(op, kZipOsDos);
|
||||
PUT16(op, gflags);
|
||||
PUT16(op, method);
|
||||
PUT16(op, mtime);
|
||||
PUT16(op, mdate);
|
||||
PUT32(op, crc);
|
||||
PUT32(op, compsize);
|
||||
PUT32(op, uncompsize);
|
||||
PUT16(op, namesize);
|
||||
PUT16(op, 0); /* extra */
|
||||
return mempcpy(op, name, namesize);
|
||||
}
|
||||
|
||||
static void EmitZipCdirHdr(unsigned char *op, const void *name, size_t namesize,
|
||||
uint32_t crc, uint8_t era, uint16_t gflags,
|
||||
uint16_t method, uint16_t mtime, uint16_t mdate,
|
||||
uint16_t iattrs, uint16_t dosmode, uint16_t unixmode,
|
||||
size_t compsize, size_t uncompsize,
|
||||
size_t commentsize) {
|
||||
PUT32(op, kZipCfileHdrMagic);
|
||||
PUT8(op, kZipCosmopolitanVersion);
|
||||
PUT8(op, kZipOsUnix);
|
||||
PUT8(op, era);
|
||||
PUT8(op, kZipOsDos);
|
||||
PUT16(op, gflags);
|
||||
PUT16(op, method);
|
||||
PUT16(op, mtime);
|
||||
PUT16(op, mdate);
|
||||
PUT32(op, crc);
|
||||
PUT32(op, compsize);
|
||||
PUT32(op, uncompsize);
|
||||
PUT16(op, namesize);
|
||||
PUT16(op, 0); /* extra size */
|
||||
PUT16(op, commentsize);
|
||||
PUT16(op, 0); /* disk */
|
||||
PUT16(op, iattrs);
|
||||
PUT16(op, dosmode);
|
||||
PUT16(op, unixmode);
|
||||
PUT32(op, 0); /* RELOCATE ME (kZipCfileOffsetOffset) */
|
||||
memcpy(op, name, namesize);
|
||||
}
|
||||
|
||||
void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize,
|
||||
const unsigned char *data, struct stat *st) {
|
||||
z_stream zs;
|
||||
uint8_t era;
|
||||
uint32_t crc;
|
||||
unsigned char *lfile, *cfile;
|
||||
struct ElfWriterSymRef lfilesym;
|
||||
size_t lfilehdrsize, uncompsize, compsize, commentsize;
|
||||
uint16_t method, gflags, mtime, mdate, iattrs, dosmode;
|
||||
|
||||
compsize = st->st_size;
|
||||
uncompsize = st->st_size;
|
||||
CHECK_LE(uncompsize, UINT32_MAX);
|
||||
lfilehdrsize = kZipLfileHdrMinSize + namesize;
|
||||
crc = crc32_z(0, data, uncompsize);
|
||||
GetDosLocalTime(st->st_mtim.tv_sec, &mtime, &mdate);
|
||||
gflags = IsPureAscii(name, namesize) ? 0 : kZipGflagUtf8;
|
||||
commentsize = kZipCdirHdrLinkableSize - (kZipCfileHdrMinSize + namesize);
|
||||
iattrs = IsPureAscii(data, st->st_size) ? kZipIattrAscii : kZipIattrBinary;
|
||||
dosmode = !(st->st_mode & 0200) ? kNtFileAttributeReadonly : 0;
|
||||
method = (st->st_size >= kMinCompressSize && ShouldCompress(name, namesize))
|
||||
? kZipCompressionDeflate
|
||||
: kZipCompressionNone;
|
||||
|
||||
/* emit embedded file content w/ pkzip local file header */
|
||||
elfwriter_align(elf, kZipCdirAlign, 0);
|
||||
elfwriter_startsection(elf,
|
||||
gc(xasprintf("%s%s", ZIP_LOCALFILE_SECTION, name)),
|
||||
SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
||||
if (method == kZipCompressionDeflate) {
|
||||
CHECK_EQ(Z_OK, deflateInit2(memset(&zs, 0, sizeof(zs)),
|
||||
Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
|
||||
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY));
|
||||
zs.next_in = data;
|
||||
zs.avail_in = uncompsize;
|
||||
zs.next_out = ((lfile = elfwriter_reserve(
|
||||
elf, (lfilehdrsize +
|
||||
(zs.avail_out = compressBound(uncompsize))))) +
|
||||
lfilehdrsize);
|
||||
CHECK_EQ(Z_STREAM_END, deflate(&zs, Z_FINISH));
|
||||
CHECK_EQ(Z_OK, deflateEnd(&zs));
|
||||
if (zs.total_out < uncompsize) {
|
||||
compsize = zs.total_out;
|
||||
} else {
|
||||
method = kZipCompressionNone;
|
||||
}
|
||||
} else {
|
||||
lfile = elfwriter_reserve(elf, lfilehdrsize + uncompsize);
|
||||
}
|
||||
if (method == kZipCompressionNone) {
|
||||
memcpy(lfile + lfilehdrsize, data, uncompsize);
|
||||
}
|
||||
era = (gflags || method) ? kZipEra1993 : kZipEra1989;
|
||||
EmitZipLfileHdr(lfile, name, namesize, crc, era, gflags, method, mtime, mdate,
|
||||
compsize, uncompsize);
|
||||
elfwriter_commit(elf, lfilehdrsize + compsize);
|
||||
lfilesym = elfwriter_appendsym(elf, gc(xasprintf("%s%s", "zip+lfile:", name)),
|
||||
ELF64_ST_INFO(STB_LOCAL, STT_OBJECT),
|
||||
STV_DEFAULT, 0, lfilehdrsize);
|
||||
elfwriter_appendsym(elf, name, ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
||||
STV_DEFAULT, lfilehdrsize, compsize);
|
||||
elfwriter_finishsection(elf);
|
||||
|
||||
/* emit central directory record */
|
||||
elfwriter_align(elf, kZipCdirAlign, 0);
|
||||
elfwriter_startsection(elf,
|
||||
gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)),
|
||||
SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
||||
EmitZipCdirHdr((cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSize)),
|
||||
name, namesize, crc, era, gflags, method, mtime, mdate, iattrs,
|
||||
dosmode, st->st_mode, compsize, uncompsize, commentsize);
|
||||
elfwriter_appendsym(elf, gc(xasprintf("%s%s", "zip+cdir:", name)),
|
||||
ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), STV_DEFAULT, 0,
|
||||
kZipCdirHdrLinkableSize);
|
||||
elfwriter_appendrela(elf, kZipCfileOffsetOffset, lfilesym, R_X86_64_32,
|
||||
-IMAGE_BASE_VIRTUAL);
|
||||
elfwriter_commit(elf, kZipCdirHdrLinkableSize);
|
||||
elfwriter_finishsection(elf);
|
||||
}
|
||||
|
||||
void ProcessFile(struct ElfWriter *elf, const char *path) {
|
||||
int fd;
|
||||
void *map;
|
||||
struct stat st;
|
||||
CHECK_NE(-1, (fd = open(path, O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
EmitZip(elf, path, strlen(path), map, &st);
|
||||
CHECK_NE(-1, munmap(map, st.st_size));
|
||||
CHECK_NE(-1, close(fd));
|
||||
}
|
||||
|
||||
void PullEndOfCentralDirectoryIntoLinkage(struct ElfWriter *elf) {
|
||||
elfwriter_align(elf, 1, 0);
|
||||
elfwriter_startsection(elf, ".yoink", SHT_PROGBITS,
|
||||
SHF_ALLOC | SHF_EXECINSTR);
|
||||
elfwriter_yoink(elf, "__zip_start");
|
||||
elfwriter_yoink(elf, "__zip_end");
|
||||
elfwriter_finishsection(elf);
|
||||
}
|
||||
|
||||
void CheckFilenameKosher(const char *path) {
|
||||
CHECK_LE(strlen(path), PATH_MAX);
|
||||
CHECK(!startswith(path, "/"));
|
||||
CHECK(!strstr(path, ".."));
|
||||
}
|
||||
|
||||
void zipobj(int argc, char **argv) {
|
||||
size_t i;
|
||||
struct ElfWriter *elf;
|
||||
CHECK_LT(argc, UINT16_MAX / 3 - 64); /* ELF 64k section limit */
|
||||
GetOpts(&argc, &argv);
|
||||
for (i = 0; i < argc; ++i) CheckFilenameKosher(argv[i]);
|
||||
elf = elfwriter_open(outpath_, 0644);
|
||||
elfwriter_cargoculting(elf);
|
||||
for (i = 0; i < argc; ++i) ProcessFile(elf, argv[i]);
|
||||
PullEndOfCentralDirectoryIntoLinkage(elf);
|
||||
elfwriter_close(elf);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
zipobj(argc, argv);
|
||||
return 0;
|
||||
}
|
193
tool/cc/c11.l
Normal file
193
tool/cc/c11.l
Normal file
|
@ -0,0 +1,193 @@
|
|||
/* http://www.quut.com/c/ANSI-C-grammar-l-2011.html */
|
||||
|
||||
%e 1019
|
||||
%p 2807
|
||||
%n 371
|
||||
%k 284
|
||||
%a 1213
|
||||
%o 1117
|
||||
|
||||
O [0-7]
|
||||
D [0-9]
|
||||
NZ [1-9]
|
||||
L [a-zA-Z_]
|
||||
A [a-zA-Z_0-9]
|
||||
H [a-fA-F0-9]
|
||||
HP (0[xX])
|
||||
E ([Ee][+-]?{D}+)
|
||||
P ([Pp][+-]?{D}+)
|
||||
FS (f|F|l|L)
|
||||
IS (((u|U)(l|L|ll|LL)?)|((l|L|ll|LL)(u|U)?))
|
||||
CP (u|U|L)
|
||||
SP (u8|u|U|L)
|
||||
ES (\\(['"\?\\abfnrtv]|[0-7]{1,3}|x[a-fA-F0-9]+))
|
||||
WS [ \t\v\n\f]
|
||||
|
||||
%{
|
||||
#include <stdio.h>
|
||||
#include "y.tab.h"
|
||||
|
||||
extern void yyerror(const char *); /* prints grammar violation message */
|
||||
|
||||
extern int sym_type(const char *); /* returns type from symbol table */
|
||||
|
||||
#define sym_type(identifier) IDENTIFIER /* with no symbol table, fake it */
|
||||
|
||||
static void comment(void);
|
||||
static int check_type(void);
|
||||
%}
|
||||
|
||||
%%
|
||||
"/*" { comment(); }
|
||||
"//".* { /* consume //-comment */ }
|
||||
|
||||
"auto" { return(AUTO); }
|
||||
"break" { return(BREAK); }
|
||||
"case" { return(CASE); }
|
||||
"char" { return(CHAR); }
|
||||
"const" { return(CONST); }
|
||||
"continue" { return(CONTINUE); }
|
||||
"default" { return(DEFAULT); }
|
||||
"do" { return(DO); }
|
||||
"double" { return(DOUBLE); }
|
||||
"else" { return(ELSE); }
|
||||
"enum" { return(ENUM); }
|
||||
"extern" { return(EXTERN); }
|
||||
"float" { return(FLOAT); }
|
||||
"for" { return(FOR); }
|
||||
"goto" { return(GOTO); }
|
||||
"if" { return(IF); }
|
||||
"inline" { return(INLINE); }
|
||||
"int" { return(INT); }
|
||||
"long" { return(LONG); }
|
||||
"register" { return(REGISTER); }
|
||||
"restrict" { return(RESTRICT); }
|
||||
"return" { return(RETURN); }
|
||||
"short" { return(SHORT); }
|
||||
"signed" { return(SIGNED); }
|
||||
"sizeof" { return(SIZEOF); }
|
||||
"static" { return(STATIC); }
|
||||
"struct" { return(STRUCT); }
|
||||
"switch" { return(SWITCH); }
|
||||
"typedef" { return(TYPEDEF); }
|
||||
"union" { return(UNION); }
|
||||
"unsigned" { return(UNSIGNED); }
|
||||
"void" { return(VOID); }
|
||||
"volatile" { return(VOLATILE); }
|
||||
"while" { return(WHILE); }
|
||||
"_Alignas" { return ALIGNAS; }
|
||||
"_Alignof" { return ALIGNOF; }
|
||||
"_Atomic" { return ATOMIC; }
|
||||
"_Bool" { return BOOL; }
|
||||
"_Complex" { return COMPLEX; }
|
||||
"_Generic" { return GENERIC; }
|
||||
"_Imaginary" { return IMAGINARY; }
|
||||
"_Noreturn" { return NORETURN; }
|
||||
"_Static_assert" { return STATIC_ASSERT; }
|
||||
"_Thread_local" { return THREAD_LOCAL; }
|
||||
"__func__" { return FUNC_NAME; }
|
||||
|
||||
{L}{A}* { return check_type(); }
|
||||
|
||||
{HP}{H}+{IS}? { return I_CONSTANT; }
|
||||
{NZ}{D}*{IS}? { return I_CONSTANT; }
|
||||
"0"{O}*{IS}? { return I_CONSTANT; }
|
||||
{CP}?"'"([^'\\\n]|{ES})+"'" { return I_CONSTANT; }
|
||||
|
||||
{D}+{E}{FS}? { return F_CONSTANT; }
|
||||
{D}*"."{D}+{E}?{FS}? { return F_CONSTANT; }
|
||||
{D}+"."{E}?{FS}? { return F_CONSTANT; }
|
||||
{HP}{H}+{P}{FS}? { return F_CONSTANT; }
|
||||
{HP}{H}*"."{H}+{P}{FS}? { return F_CONSTANT; }
|
||||
{HP}{H}+"."{P}{FS}? { return F_CONSTANT; }
|
||||
|
||||
({SP}?\"([^"\\\n]|{ES})*\"{WS}*)+ { return STRING_LITERAL; }
|
||||
|
||||
"..." { return ELLIPSIS; }
|
||||
">>=" { return RIGHT_ASSIGN; }
|
||||
"<<=" { return LEFT_ASSIGN; }
|
||||
"+=" { return ADD_ASSIGN; }
|
||||
"-=" { return SUB_ASSIGN; }
|
||||
"*=" { return MUL_ASSIGN; }
|
||||
"/=" { return DIV_ASSIGN; }
|
||||
"%=" { return MOD_ASSIGN; }
|
||||
"&=" { return AND_ASSIGN; }
|
||||
"^=" { return XOR_ASSIGN; }
|
||||
"|=" { return OR_ASSIGN; }
|
||||
">>" { return RIGHT_OP; }
|
||||
"<<" { return LEFT_OP; }
|
||||
"++" { return INC_OP; }
|
||||
"--" { return DEC_OP; }
|
||||
"->" { return PTR_OP; }
|
||||
"&&" { return AND_OP; }
|
||||
"||" { return OR_OP; }
|
||||
"<=" { return LE_OP; }
|
||||
">=" { return GE_OP; }
|
||||
"==" { return EQ_OP; }
|
||||
"!=" { return NE_OP; }
|
||||
";" { return ';'; }
|
||||
("{"|"<%") { return '{'; }
|
||||
("}"|"%>") { return '}'; }
|
||||
"," { return ','; }
|
||||
":" { return ':'; }
|
||||
"=" { return '='; }
|
||||
"(" { return '('; }
|
||||
")" { return ')'; }
|
||||
("["|"<:") { return '['; }
|
||||
("]"|":>") { return ']'; }
|
||||
"." { return '.'; }
|
||||
"&" { return '&'; }
|
||||
"!" { return '!'; }
|
||||
"~" { return '~'; }
|
||||
"-" { return '-'; }
|
||||
"+" { return '+'; }
|
||||
"*" { return '*'; }
|
||||
"/" { return '/'; }
|
||||
"%" { return '%'; }
|
||||
"<" { return '<'; }
|
||||
">" { return '>'; }
|
||||
"^" { return '^'; }
|
||||
"|" { return '|'; }
|
||||
"?" { return '?'; }
|
||||
|
||||
{WS}+ { /* whitespace separates tokens */ }
|
||||
. { /* discard bad characters */ }
|
||||
|
||||
%%
|
||||
|
||||
int yywrap(void) /* called at end of input */
|
||||
{
|
||||
return 1; /* terminate now */
|
||||
}
|
||||
|
||||
static void comment(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = input()) != 0)
|
||||
if (c == '*')
|
||||
{
|
||||
while ((c = input()) == '*')
|
||||
;
|
||||
|
||||
if (c == '/')
|
||||
return;
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
}
|
||||
yyerror("unterminated comment");
|
||||
}
|
||||
|
||||
static int check_type(void)
|
||||
{
|
||||
switch (sym_type(yytext))
|
||||
{
|
||||
case TYPEDEF_NAME: /* previously defined */
|
||||
return TYPEDEF_NAME;
|
||||
case ENUMERATION_CONSTANT: /* previously defined */
|
||||
return ENUMERATION_CONSTANT;
|
||||
default: /* includes undefined */
|
||||
return IDENTIFIER;
|
||||
}
|
||||
}
|
535
tool/cc/c11.y
Normal file
535
tool/cc/c11.y
Normal file
|
@ -0,0 +1,535 @@
|
|||
/* http://www.quut.com/c/ANSI-C-grammar-y-2011.html */
|
||||
|
||||
%token IDENTIFIER I_CONSTANT F_CONSTANT STRING_LITERAL FUNC_NAME SIZEOF
|
||||
%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
|
||||
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
|
||||
%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
|
||||
%token XOR_ASSIGN OR_ASSIGN
|
||||
%token TYPEDEF_NAME ENUMERATION_CONSTANT
|
||||
|
||||
%token TYPEDEF EXTERN STATIC AUTO REGISTER INLINE
|
||||
%token CONST RESTRICT VOLATILE
|
||||
%token BOOL CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE VOID
|
||||
%token COMPLEX IMAGINARY
|
||||
%token STRUCT UNION ENUM ELLIPSIS
|
||||
|
||||
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
|
||||
|
||||
%token ALIGNAS ALIGNOF ATOMIC GENERIC NORETURN STATIC_ASSERT THREAD_LOCAL
|
||||
|
||||
%start translation_unit
|
||||
%%
|
||||
|
||||
primary_expression
|
||||
: IDENTIFIER
|
||||
| constant
|
||||
| string
|
||||
| '(' expression ')'
|
||||
| generic_selection
|
||||
;
|
||||
|
||||
constant
|
||||
: I_CONSTANT /* includes character_constant */
|
||||
| F_CONSTANT
|
||||
| ENUMERATION_CONSTANT /* after it has been defined as such */
|
||||
;
|
||||
|
||||
enumeration_constant /* before it has been defined as such */
|
||||
: IDENTIFIER
|
||||
;
|
||||
|
||||
string
|
||||
: STRING_LITERAL
|
||||
| FUNC_NAME
|
||||
;
|
||||
|
||||
generic_selection
|
||||
: GENERIC '(' assignment_expression ',' generic_assoc_list ')'
|
||||
;
|
||||
|
||||
generic_assoc_list
|
||||
: generic_association
|
||||
| generic_assoc_list ',' generic_association
|
||||
;
|
||||
|
||||
generic_association
|
||||
: type_name ':' assignment_expression
|
||||
| DEFAULT ':' assignment_expression
|
||||
;
|
||||
|
||||
postfix_expression
|
||||
: primary_expression
|
||||
| postfix_expression '[' expression ']'
|
||||
| postfix_expression '(' ')'
|
||||
| postfix_expression '(' argument_expression_list ')'
|
||||
| postfix_expression '.' IDENTIFIER
|
||||
| postfix_expression PTR_OP IDENTIFIER
|
||||
| postfix_expression INC_OP
|
||||
| postfix_expression DEC_OP
|
||||
| '(' type_name ')' '{' initializer_list '}'
|
||||
| '(' type_name ')' '{' initializer_list ',' '}'
|
||||
;
|
||||
|
||||
argument_expression_list
|
||||
: assignment_expression
|
||||
| argument_expression_list ',' assignment_expression
|
||||
;
|
||||
|
||||
unary_expression
|
||||
: postfix_expression
|
||||
| INC_OP unary_expression
|
||||
| DEC_OP unary_expression
|
||||
| unary_operator cast_expression
|
||||
| SIZEOF unary_expression
|
||||
| SIZEOF '(' type_name ')'
|
||||
| ALIGNOF '(' type_name ')'
|
||||
;
|
||||
|
||||
unary_operator
|
||||
: '&'
|
||||
| '*'
|
||||
| '+'
|
||||
| '-'
|
||||
| '~'
|
||||
| '!'
|
||||
;
|
||||
|
||||
cast_expression
|
||||
: unary_expression
|
||||
| '(' type_name ')' cast_expression
|
||||
;
|
||||
|
||||
multiplicative_expression
|
||||
: cast_expression
|
||||
| multiplicative_expression '*' cast_expression
|
||||
| multiplicative_expression '/' cast_expression
|
||||
| multiplicative_expression '%' cast_expression
|
||||
;
|
||||
|
||||
additive_expression
|
||||
: multiplicative_expression
|
||||
| additive_expression '+' multiplicative_expression
|
||||
| additive_expression '-' multiplicative_expression
|
||||
;
|
||||
|
||||
shift_expression
|
||||
: additive_expression
|
||||
| shift_expression LEFT_OP additive_expression
|
||||
| shift_expression RIGHT_OP additive_expression
|
||||
;
|
||||
|
||||
relational_expression
|
||||
: shift_expression
|
||||
| relational_expression '<' shift_expression
|
||||
| relational_expression '>' shift_expression
|
||||
| relational_expression LE_OP shift_expression
|
||||
| relational_expression GE_OP shift_expression
|
||||
;
|
||||
|
||||
equality_expression
|
||||
: relational_expression
|
||||
| equality_expression EQ_OP relational_expression
|
||||
| equality_expression NE_OP relational_expression
|
||||
;
|
||||
|
||||
and_expression
|
||||
: equality_expression
|
||||
| and_expression '&' equality_expression
|
||||
;
|
||||
|
||||
exclusive_or_expression
|
||||
: and_expression
|
||||
| exclusive_or_expression '^' and_expression
|
||||
;
|
||||
|
||||
inclusive_or_expression
|
||||
: exclusive_or_expression
|
||||
| inclusive_or_expression '|' exclusive_or_expression
|
||||
;
|
||||
|
||||
logical_and_expression
|
||||
: inclusive_or_expression
|
||||
| logical_and_expression AND_OP inclusive_or_expression
|
||||
;
|
||||
|
||||
logical_or_expression
|
||||
: logical_and_expression
|
||||
| logical_or_expression OR_OP logical_and_expression
|
||||
;
|
||||
|
||||
conditional_expression
|
||||
: logical_or_expression
|
||||
| logical_or_expression '?' expression ':' conditional_expression
|
||||
;
|
||||
|
||||
assignment_expression
|
||||
: conditional_expression
|
||||
| unary_expression assignment_operator assignment_expression
|
||||
;
|
||||
|
||||
assignment_operator
|
||||
: '='
|
||||
| MUL_ASSIGN
|
||||
| DIV_ASSIGN
|
||||
| MOD_ASSIGN
|
||||
| ADD_ASSIGN
|
||||
| SUB_ASSIGN
|
||||
| LEFT_ASSIGN
|
||||
| RIGHT_ASSIGN
|
||||
| AND_ASSIGN
|
||||
| XOR_ASSIGN
|
||||
| OR_ASSIGN
|
||||
;
|
||||
|
||||
expression
|
||||
: assignment_expression
|
||||
| expression ',' assignment_expression
|
||||
;
|
||||
|
||||
constant_expression
|
||||
: conditional_expression /* with constraints */
|
||||
;
|
||||
|
||||
declaration
|
||||
: declaration_specifiers ';'
|
||||
| declaration_specifiers init_declarator_list ';'
|
||||
| static_assert_declaration
|
||||
;
|
||||
|
||||
declaration_specifiers
|
||||
: storage_class_specifier declaration_specifiers
|
||||
| storage_class_specifier
|
||||
| type_specifier declaration_specifiers
|
||||
| type_specifier
|
||||
| type_qualifier declaration_specifiers
|
||||
| type_qualifier
|
||||
| function_specifier declaration_specifiers
|
||||
| function_specifier
|
||||
| alignment_specifier declaration_specifiers
|
||||
| alignment_specifier
|
||||
;
|
||||
|
||||
init_declarator_list
|
||||
: init_declarator
|
||||
| init_declarator_list ',' init_declarator
|
||||
;
|
||||
|
||||
init_declarator
|
||||
: declarator '=' initializer
|
||||
| declarator
|
||||
;
|
||||
|
||||
storage_class_specifier
|
||||
: TYPEDEF /* identifiers must be flagged as TYPEDEF_NAME */
|
||||
| EXTERN
|
||||
| STATIC
|
||||
| THREAD_LOCAL
|
||||
| AUTO
|
||||
| REGISTER
|
||||
;
|
||||
|
||||
type_specifier
|
||||
: VOID
|
||||
| CHAR
|
||||
| SHORT
|
||||
| INT
|
||||
| LONG
|
||||
| FLOAT
|
||||
| DOUBLE
|
||||
| SIGNED
|
||||
| UNSIGNED
|
||||
| BOOL
|
||||
| COMPLEX
|
||||
| IMAGINARY /* non-mandated extension */
|
||||
| atomic_type_specifier
|
||||
| struct_or_union_specifier
|
||||
| enum_specifier
|
||||
| TYPEDEF_NAME /* after it has been defined as such */
|
||||
;
|
||||
|
||||
struct_or_union_specifier
|
||||
: struct_or_union '{' struct_declaration_list '}'
|
||||
| struct_or_union IDENTIFIER '{' struct_declaration_list '}'
|
||||
| struct_or_union IDENTIFIER
|
||||
;
|
||||
|
||||
struct_or_union
|
||||
: STRUCT
|
||||
| UNION
|
||||
;
|
||||
|
||||
struct_declaration_list
|
||||
: struct_declaration
|
||||
| struct_declaration_list struct_declaration
|
||||
;
|
||||
|
||||
struct_declaration
|
||||
: specifier_qualifier_list ';' /* for anonymous struct/union */
|
||||
| specifier_qualifier_list struct_declarator_list ';'
|
||||
| static_assert_declaration
|
||||
;
|
||||
|
||||
specifier_qualifier_list
|
||||
: type_specifier specifier_qualifier_list
|
||||
| type_specifier
|
||||
| type_qualifier specifier_qualifier_list
|
||||
| type_qualifier
|
||||
;
|
||||
|
||||
struct_declarator_list
|
||||
: struct_declarator
|
||||
| struct_declarator_list ',' struct_declarator
|
||||
;
|
||||
|
||||
struct_declarator
|
||||
: ':' constant_expression
|
||||
| declarator ':' constant_expression
|
||||
| declarator
|
||||
;
|
||||
|
||||
enum_specifier
|
||||
: ENUM '{' enumerator_list '}'
|
||||
| ENUM '{' enumerator_list ',' '}'
|
||||
| ENUM IDENTIFIER '{' enumerator_list '}'
|
||||
| ENUM IDENTIFIER '{' enumerator_list ',' '}'
|
||||
| ENUM IDENTIFIER
|
||||
;
|
||||
|
||||
enumerator_list
|
||||
: enumerator
|
||||
| enumerator_list ',' enumerator
|
||||
;
|
||||
|
||||
enumerator /* identifiers must be flagged as ENUMERATION_CONSTANT */
|
||||
: enumeration_constant '=' constant_expression
|
||||
| enumeration_constant
|
||||
;
|
||||
|
||||
atomic_type_specifier
|
||||
: ATOMIC '(' type_name ')'
|
||||
;
|
||||
|
||||
type_qualifier
|
||||
: CONST
|
||||
| RESTRICT
|
||||
| VOLATILE
|
||||
| ATOMIC
|
||||
;
|
||||
|
||||
function_specifier
|
||||
: INLINE
|
||||
| NORETURN
|
||||
;
|
||||
|
||||
alignment_specifier
|
||||
: ALIGNAS '(' type_name ')'
|
||||
| ALIGNAS '(' constant_expression ')'
|
||||
;
|
||||
|
||||
declarator
|
||||
: pointer direct_declarator
|
||||
| direct_declarator
|
||||
;
|
||||
|
||||
direct_declarator
|
||||
: IDENTIFIER
|
||||
| '(' declarator ')'
|
||||
| direct_declarator '[' ']'
|
||||
| direct_declarator '[' '*' ']'
|
||||
| direct_declarator '[' STATIC type_qualifier_list assignment_expression ']'
|
||||
| direct_declarator '[' STATIC assignment_expression ']'
|
||||
| direct_declarator '[' type_qualifier_list '*' ']'
|
||||
| direct_declarator '[' type_qualifier_list STATIC assignment_expression ']'
|
||||
| direct_declarator '[' type_qualifier_list assignment_expression ']'
|
||||
| direct_declarator '[' type_qualifier_list ']'
|
||||
| direct_declarator '[' assignment_expression ']'
|
||||
| direct_declarator '(' parameter_type_list ')'
|
||||
| direct_declarator '(' ')'
|
||||
| direct_declarator '(' identifier_list ')'
|
||||
;
|
||||
|
||||
pointer
|
||||
: '*' type_qualifier_list pointer
|
||||
| '*' type_qualifier_list
|
||||
| '*' pointer
|
||||
| '*'
|
||||
;
|
||||
|
||||
type_qualifier_list
|
||||
: type_qualifier
|
||||
| type_qualifier_list type_qualifier
|
||||
;
|
||||
|
||||
|
||||
parameter_type_list
|
||||
: parameter_list ',' ELLIPSIS
|
||||
| parameter_list
|
||||
;
|
||||
|
||||
parameter_list
|
||||
: parameter_declaration
|
||||
| parameter_list ',' parameter_declaration
|
||||
;
|
||||
|
||||
parameter_declaration
|
||||
: declaration_specifiers declarator
|
||||
| declaration_specifiers abstract_declarator
|
||||
| declaration_specifiers
|
||||
;
|
||||
|
||||
identifier_list
|
||||
: IDENTIFIER
|
||||
| identifier_list ',' IDENTIFIER
|
||||
;
|
||||
|
||||
type_name
|
||||
: specifier_qualifier_list abstract_declarator
|
||||
| specifier_qualifier_list
|
||||
;
|
||||
|
||||
abstract_declarator
|
||||
: pointer direct_abstract_declarator
|
||||
| pointer
|
||||
| direct_abstract_declarator
|
||||
;
|
||||
|
||||
direct_abstract_declarator
|
||||
: '(' abstract_declarator ')'
|
||||
| '[' ']'
|
||||
| '[' '*' ']'
|
||||
| '[' STATIC type_qualifier_list assignment_expression ']'
|
||||
| '[' STATIC assignment_expression ']'
|
||||
| '[' type_qualifier_list STATIC assignment_expression ']'
|
||||
| '[' type_qualifier_list assignment_expression ']'
|
||||
| '[' type_qualifier_list ']'
|
||||
| '[' assignment_expression ']'
|
||||
| direct_abstract_declarator '[' ']'
|
||||
| direct_abstract_declarator '[' '*' ']'
|
||||
| direct_abstract_declarator '[' STATIC type_qualifier_list assignment_expression ']'
|
||||
| direct_abstract_declarator '[' STATIC assignment_expression ']'
|
||||
| direct_abstract_declarator '[' type_qualifier_list assignment_expression ']'
|
||||
| direct_abstract_declarator '[' type_qualifier_list STATIC assignment_expression ']'
|
||||
| direct_abstract_declarator '[' type_qualifier_list ']'
|
||||
| direct_abstract_declarator '[' assignment_expression ']'
|
||||
| '(' ')'
|
||||
| '(' parameter_type_list ')'
|
||||
| direct_abstract_declarator '(' ')'
|
||||
| direct_abstract_declarator '(' parameter_type_list ')'
|
||||
;
|
||||
|
||||
initializer
|
||||
: '{' initializer_list '}'
|
||||
| '{' initializer_list ',' '}'
|
||||
| assignment_expression
|
||||
;
|
||||
|
||||
initializer_list
|
||||
: designation initializer
|
||||
| initializer
|
||||
| initializer_list ',' designation initializer
|
||||
| initializer_list ',' initializer
|
||||
;
|
||||
|
||||
designation
|
||||
: designator_list '='
|
||||
;
|
||||
|
||||
designator_list
|
||||
: designator
|
||||
| designator_list designator
|
||||
;
|
||||
|
||||
designator
|
||||
: '[' constant_expression ']'
|
||||
| '.' IDENTIFIER
|
||||
;
|
||||
|
||||
static_assert_declaration
|
||||
: STATIC_ASSERT '(' constant_expression ',' STRING_LITERAL ')' ';'
|
||||
;
|
||||
|
||||
statement
|
||||
: labeled_statement
|
||||
| compound_statement
|
||||
| expression_statement
|
||||
| selection_statement
|
||||
| iteration_statement
|
||||
| jump_statement
|
||||
;
|
||||
|
||||
labeled_statement
|
||||
: IDENTIFIER ':' statement
|
||||
| CASE constant_expression ':' statement
|
||||
| DEFAULT ':' statement
|
||||
;
|
||||
|
||||
compound_statement
|
||||
: '{' '}'
|
||||
| '{' block_item_list '}'
|
||||
;
|
||||
|
||||
block_item_list
|
||||
: block_item
|
||||
| block_item_list block_item
|
||||
;
|
||||
|
||||
block_item
|
||||
: declaration
|
||||
| statement
|
||||
;
|
||||
|
||||
expression_statement
|
||||
: ';'
|
||||
| expression ';'
|
||||
;
|
||||
|
||||
selection_statement
|
||||
: IF '(' expression ')' statement ELSE statement
|
||||
| IF '(' expression ')' statement
|
||||
| SWITCH '(' expression ')' statement
|
||||
;
|
||||
|
||||
iteration_statement
|
||||
: WHILE '(' expression ')' statement
|
||||
| DO statement WHILE '(' expression ')' ';'
|
||||
| FOR '(' expression_statement expression_statement ')' statement
|
||||
| FOR '(' expression_statement expression_statement expression ')' statement
|
||||
| FOR '(' declaration expression_statement ')' statement
|
||||
| FOR '(' declaration expression_statement expression ')' statement
|
||||
;
|
||||
|
||||
jump_statement
|
||||
: GOTO IDENTIFIER ';'
|
||||
| CONTINUE ';'
|
||||
| BREAK ';'
|
||||
| RETURN ';'
|
||||
| RETURN expression ';'
|
||||
;
|
||||
|
||||
translation_unit
|
||||
: external_declaration
|
||||
| translation_unit external_declaration
|
||||
;
|
||||
|
||||
external_declaration
|
||||
: function_definition
|
||||
| declaration
|
||||
;
|
||||
|
||||
function_definition
|
||||
: declaration_specifiers declarator declaration_list compound_statement
|
||||
| declaration_specifiers declarator compound_statement
|
||||
;
|
||||
|
||||
declaration_list
|
||||
: declaration
|
||||
| declaration_list declaration
|
||||
;
|
||||
|
||||
%%
|
||||
#include <stdio.h>
|
||||
|
||||
void yyerror(const char *s) {
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "*** %s\n", s);
|
||||
}
|
11
tool/cc/cc.mk
Normal file
11
tool/cc/cc.mk
Normal file
|
@ -0,0 +1,11 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_CC
|
||||
|
||||
o/$(MODE)/tool/cc/c11.c: tool/cc/c11.l o/$(MODE)/third_party/lex/lex.com.dbg
|
||||
@mkdir -p $(dir $@)
|
||||
o/$(MODE)/third_party/lex/lex.com.dbg -o $@ $<
|
||||
|
||||
.PHONY: o/$(MODE)/tool/cc
|
||||
o/$(MODE)/tool/cc:
|
33
tool/debug/debug.mk
Normal file
33
tool/debug/debug.mk
Normal file
|
@ -0,0 +1,33 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_DEBUG
|
||||
|
||||
TOOL_DEBUG_SRCS := $(wildcard tool/debug/*.c)
|
||||
TOOL_DEBUG_OBJS = $(TOOL_DEBUG_SRCS:%.c=o/$(MODE)/%.o)
|
||||
TOOL_DEBUG_COMS = $(TOOL_DEBUG_OBJS:%.o=%.com)
|
||||
|
||||
TOOL_DEBUG_DEPS := $(call uniq, \
|
||||
$(LIBC_STR) \
|
||||
$(LIBC_RUNTIME) \
|
||||
$(LIBC_STDIO) \
|
||||
$(LIBC_X) \
|
||||
$(LIBC_LOG))
|
||||
|
||||
TOOL_DEBUG_BINS = \
|
||||
$(TOOL_DEBUG_COMS) \
|
||||
$(TOOL_DEBUG_COMS:%=%.dbg)
|
||||
|
||||
o/$(MODE)/tool/debug/%.com.dbg: \
|
||||
$(TOOL_DEBUG_DEPS) \
|
||||
o/$(MODE)/tool/debug/%.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
$(TOOL_DEBUG_OBJS): \
|
||||
$(BUILD_FILES) \
|
||||
tool/debug/debug.mk
|
||||
|
||||
.PHONY: o/$(MODE)/tool/debug
|
||||
o/$(MODE)/tool/debug: $(TOOL_DEBUG_BINS) $(TOOL_DEBUG_CHECKS)
|
66
tool/decode/decode.mk
Normal file
66
tool/decode/decode.mk
Normal file
|
@ -0,0 +1,66 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_DECODE
|
||||
|
||||
TOOL_DECODE_FILES := $(wildcard tool/decode/*)
|
||||
TOOL_DECODE_HDRS = $(filter %.h,$(TOOL_DECODE_FILES))
|
||||
TOOL_DECODE_SRCS = $(filter %.c,$(TOOL_DECODE_FILES))
|
||||
TOOL_DECODE_COMS = $(TOOL_DECODE_OBJS:%.o=%.com)
|
||||
|
||||
TOOL_DECODE_OBJS = \
|
||||
$(TOOL_DECODE_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(TOOL_DECODE_SRCS:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_DECODE_BINS = \
|
||||
$(TOOL_DECODE_COMS) \
|
||||
$(TOOL_DECODE_COMS:%=%.dbg)
|
||||
|
||||
TOOL_DECODE_CHECKS = \
|
||||
$(TOOL_DECODE_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
TOOL_DECODE_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_CONV \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
TOOL_DECODE_LIB \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_XED
|
||||
|
||||
TOOL_DECODE_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_DECODE_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/tool/decode/decode.pkg: \
|
||||
$(TOOL_DECODE_OBJS) \
|
||||
$(foreach x,$(TOOL_DECODE_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/tool/decode/%.com.dbg: \
|
||||
$(TOOL_DECODE_DEPS) \
|
||||
o/$(MODE)/tool/decode/%.o \
|
||||
o/$(MODE)/tool/decode/decode.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
$(TOOL_DECODE_OBJS): \
|
||||
$(BUILD_FILES) \
|
||||
tool/decode/decode.mk
|
||||
|
||||
.PHONY: o/$(MODE)/tool/decode
|
||||
o/$(MODE)/tool/decode: \
|
||||
o/$(MODE)/tool/decode/lib \
|
||||
$(TOOL_DECODE_BINS) \
|
||||
$(TOOL_DECODE_CHECKS)
|
329
tool/decode/elf.c
Normal file
329
tool/decode/elf.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/elf/struct/rela.h"
|
||||
#include "libc/elf/struct/shdr.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "tool/decode/lib/asmcodegen.h"
|
||||
#include "tool/decode/lib/elfidnames.h"
|
||||
#include "tool/decode/lib/flagger.h"
|
||||
#include "tool/decode/lib/titlegen.h"
|
||||
|
||||
/**
|
||||
* @fileoverview ELF executable metadata disassembler.
|
||||
*/
|
||||
|
||||
static const char *path;
|
||||
static struct stat st[1];
|
||||
static Elf64_Ehdr *elf;
|
||||
|
||||
static void startfile(void) {
|
||||
showtitle("αcτµαlly pδrταblε εxεcµταblε", "tool/decode/elf", basename(path),
|
||||
NULL, &kModelineAsm);
|
||||
printf("#include \"libc/elf.h\"\n\n", path);
|
||||
}
|
||||
|
||||
static void printelfehdr(void) {
|
||||
show(".ascii", format(b1, "%`'.*s", 4, (const char *)&elf->e_ident[0]),
|
||||
"magic");
|
||||
show(".byte",
|
||||
firstnonnull(findnamebyid(&kElfClassNames[0], elf->e_ident[EI_CLASS]),
|
||||
format(b1, "%d", elf->e_ident[EI_CLASS])),
|
||||
"elf->e_ident[EI_CLASS]");
|
||||
show(".byte",
|
||||
firstnonnull(findnamebyid(kElfDataNames, elf->e_ident[EI_DATA]),
|
||||
format(b1, "%d", elf->e_ident[EI_DATA])),
|
||||
"elf->e_ident[EI_DATA]");
|
||||
show(".byte", format(b1, "%d", elf->e_ident[EI_VERSION]),
|
||||
"elf->e_ident[EI_VERSION]");
|
||||
show(".byte",
|
||||
firstnonnull(findnamebyid(kElfOsabiNames, elf->e_ident[EI_OSABI]),
|
||||
format(b1, "%d", elf->e_ident[EI_OSABI])),
|
||||
"elf->e_ident[EI_OSABI]");
|
||||
show(".byte", format(b1, "%d", elf->e_ident[EI_ABIVERSION]),
|
||||
"elf->e_ident[EI_ABIVERSION]");
|
||||
show(".byte",
|
||||
format(b1, "%d,%d,%d,%d,%d,%d,%d", elf->e_ident[EI_PAD + 0],
|
||||
elf->e_ident[EI_PAD + 1], elf->e_ident[EI_PAD + 2],
|
||||
elf->e_ident[EI_PAD + 3], elf->e_ident[EI_PAD + 4],
|
||||
elf->e_ident[EI_PAD + 5], elf->e_ident[EI_PAD + 6]),
|
||||
"padding");
|
||||
show(".org", "0x10", NULL);
|
||||
show(".short",
|
||||
firstnonnull(findnamebyid(kElfTypeNames, elf->e_type),
|
||||
format(b1, "%hd", elf->e_type)),
|
||||
"elf->e_type");
|
||||
show(".short",
|
||||
firstnonnull(findnamebyid(kElfMachineNames, elf->e_machine),
|
||||
format(b1, "%hd", elf->e_machine)),
|
||||
"elf->e_machine");
|
||||
show(".long", format(b1, "%d", elf->e_version), "elf->e_version");
|
||||
show(".quad", format(b1, "%#x", elf->e_entry), "elf->e_entry");
|
||||
show(".quad", format(b1, "%#x", elf->e_phoff), "elf->e_phoff");
|
||||
show(".quad", format(b1, "%#x", elf->e_shoff), "elf->e_shoff");
|
||||
show(".long", format(b1, "%#x", elf->e_flags), "elf->e_flags");
|
||||
show(".short", format(b1, "%hd", elf->e_ehsize), "elf->e_ehsize");
|
||||
show(".short", format(b1, "%hd", elf->e_phentsize), "elf->e_phentsize");
|
||||
show(".short", format(b1, "%hd", elf->e_phnum), "elf->e_phnum");
|
||||
show(".short", format(b1, "%hd", elf->e_shentsize), "elf->e_shentsize");
|
||||
show(".short", format(b1, "%hd", elf->e_shnum), "elf->e_shnum");
|
||||
show(".short", format(b1, "%hd", elf->e_shstrndx), "elf->e_shstrndx");
|
||||
}
|
||||
|
||||
static void printelfsegmentheader(int i) {
|
||||
Elf64_Phdr *phdr = getelfsegmentheaderaddress(elf, st->st_size, i);
|
||||
printf("/\tElf64_Phdr *phdr = getelfsegmentheaderaddress(elf, st->st_size, "
|
||||
"%d)\n",
|
||||
i);
|
||||
printf(".Lph%d:", i);
|
||||
show(".long",
|
||||
firstnonnull(findnamebyid(kElfSegmentTypeNames, phdr->p_type),
|
||||
format(b1, "%#x", phdr->p_type)),
|
||||
"phdr->p_type");
|
||||
show(".long", recreateflags(kElfSegmentFlagNames, phdr->p_flags),
|
||||
"phdr->p_flags");
|
||||
show(".quad", format(b1, "%#x", phdr->p_offset), "phdr->p_offset");
|
||||
show(".quad", format(b1, "%#x", phdr->p_vaddr), "phdr->p_vaddr");
|
||||
show(".quad", format(b1, "%#x", phdr->p_paddr), "phdr->p_paddr");
|
||||
show(".quad", format(b1, "%#x", phdr->p_filesz), "phdr->p_filesz");
|
||||
show(".quad", format(b1, "%#x", phdr->p_memsz), "phdr->p_memsz");
|
||||
show(".quad", format(b1, "%#x", phdr->p_align), "phdr->p_align");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void printelfsegmentheaders(void) {
|
||||
printf("\n");
|
||||
printf("\t.org\t%#x\n", elf->e_phoff);
|
||||
for (unsigned i = 0; i < elf->e_phnum; ++i) printelfsegmentheader(i);
|
||||
}
|
||||
|
||||
static void printelfsectionheader(int i, char *shstrtab) {
|
||||
Elf64_Shdr *shdr;
|
||||
shdr = getelfsectionheaderaddress(elf, st->st_size, i);
|
||||
printf("/\tElf64_Shdr *shdr = getelfsectionheaderaddress(elf, st->st_size, "
|
||||
"%d)\n",
|
||||
i);
|
||||
printf(".Lsh%d:", i);
|
||||
show(".long", format(b1, "%d", shdr->sh_name),
|
||||
format(b2,
|
||||
"%`'s == getelfstring(elf, st->st_size, shstrtab, shdr->sh_name)",
|
||||
getelfstring(elf, st->st_size, shstrtab, shdr->sh_name)));
|
||||
show(".long",
|
||||
firstnonnull(findnamebyid(kElfSectionTypeNames, shdr->sh_type),
|
||||
format(b1, "%d", shdr->sh_type)),
|
||||
"shdr->sh_type");
|
||||
show(".long", recreateflags(kElfSectionFlagNames, shdr->sh_flags),
|
||||
"shdr->sh_flags");
|
||||
show(".quad", format(b1, "%#x", shdr->sh_addr), "shdr->sh_addr");
|
||||
show(".quad", format(b1, "%#x", shdr->sh_offset), "shdr->sh_offset");
|
||||
show(".quad", format(b1, "%#x", shdr->sh_size), "shdr->sh_size");
|
||||
show(".long", format(b1, "%#x", shdr->sh_link), "shdr->sh_link");
|
||||
show(".long", format(b1, "%#x", shdr->sh_info), "shdr->sh_info");
|
||||
show(".quad", format(b1, "%#x", shdr->sh_addralign), "shdr->sh_addralign");
|
||||
show(".quad", format(b1, "%#x", shdr->sh_entsize), "shdr->sh_entsize");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void printelfsectionheaders(void) {
|
||||
Elf64_Half i;
|
||||
char *shstrtab = getelfsectionnamestringtable(elf, st->st_size);
|
||||
if (shstrtab) {
|
||||
printf("\n");
|
||||
printf("\t.org\t%#x\n", elf->e_shoff);
|
||||
for (i = 0; i < elf->e_shnum; ++i) {
|
||||
printelfsectionheader(i, shstrtab);
|
||||
}
|
||||
printf("\n/\t%s\n", "elf->e_shstrndx");
|
||||
printf("\t.org\t%#x\n",
|
||||
getelfsectionheaderaddress(elf, st->st_size, elf->e_shstrndx)
|
||||
->sh_offset);
|
||||
for (i = 0; i < elf->e_shnum; ++i) {
|
||||
Elf64_Shdr *shdr = getelfsectionheaderaddress(elf, st->st_size, i);
|
||||
const char *str = getelfstring(elf, st->st_size, shstrtab, shdr->sh_name);
|
||||
show(".asciz", format(b1, "%`'s", str), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void printelfsymbolinfo(Elf64_Sym *sym) {
|
||||
int bind = (sym->st_info >> 4) & 0xf;
|
||||
const char *bindname = findnamebyid(kElfSymbolBindNames, bind);
|
||||
int type = (sym->st_info >> 0) & 0xf;
|
||||
const char *typename = findnamebyid(kElfSymbolTypeNames, type);
|
||||
show(".byte",
|
||||
format(b1, "%s%s%s", bindname ? format(b2, "%s<<4", bindname) : "",
|
||||
bindname && typename ? "|" : "", firstnonnull(typename, "")),
|
||||
"sym->st_info");
|
||||
}
|
||||
|
||||
static void printelfsymbolother(Elf64_Sym *sym) {
|
||||
int visibility = sym->st_other & 0x3;
|
||||
const char *visibilityname =
|
||||
findnamebyid(kElfSymbolVisibilityNames, visibility);
|
||||
int other = sym->st_other & ~0x3;
|
||||
show(".byte",
|
||||
format(b1, "%s%s%s", firstnonnull(visibilityname, ""),
|
||||
other && visibilityname ? "+" : "",
|
||||
other ? format(b2, "%d", other) : ""),
|
||||
"sym->st_other");
|
||||
}
|
||||
|
||||
static void printelfsymbol(Elf64_Sym *sym, char *strtab, char *shstrtab) {
|
||||
show(".long", format(b1, "%d", sym->st_name),
|
||||
format(b2, "%`'s (sym->st_name)",
|
||||
getelfstring(elf, st->st_size, strtab, sym->st_name)));
|
||||
printelfsymbolinfo(sym);
|
||||
printelfsymbolother(sym);
|
||||
show(".short", format(b1, "%d", sym->st_shndx),
|
||||
format(b2, "%s sym->st_shndx",
|
||||
sym->st_shndx < 0xff00
|
||||
? format(b1, "%`'s",
|
||||
getelfstring(elf, st->st_size, shstrtab,
|
||||
getelfsectionheaderaddress(
|
||||
elf, st->st_size, sym->st_shndx)
|
||||
->sh_name))
|
||||
: findnamebyid(kElfSpecialSectionNames, sym->st_shndx)));
|
||||
show(".quad", format(b1, "%#x", sym->st_value), "sym->st_value");
|
||||
show(".quad", format(b1, "%#x", sym->st_size), "sym->st_size");
|
||||
}
|
||||
|
||||
static void printelfsymboltable(void) {
|
||||
size_t i, symcount = 0;
|
||||
Elf64_Sym *symtab = getelfsymboltable(elf, st->st_size, &symcount);
|
||||
char *strtab = getelfstringtable(elf, st->st_size);
|
||||
char *shstrtab = getelfsectionnamestringtable(elf, st->st_size);
|
||||
if (symtab && strtab) {
|
||||
printf("\n\n");
|
||||
printf("\t.org\t%#x\n", (intptr_t)symtab - (intptr_t)elf);
|
||||
for (i = 0; i < symcount; ++i) {
|
||||
printf(".Lsym%d:\n", i);
|
||||
printelfsymbol(&symtab[i], strtab, shstrtab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *getelfsymbolname(const Elf64_Ehdr *elf, size_t mapsize,
|
||||
const char *strtab, const char *shstrtab,
|
||||
const Elf64_Sym *sym) {
|
||||
char *res;
|
||||
const Elf64_Shdr *shdr;
|
||||
if (elf && sym &&
|
||||
((shstrtab && !sym->st_name &&
|
||||
ELF64_ST_TYPE(sym->st_info) == STT_SECTION &&
|
||||
(shdr = getelfsectionheaderaddress(elf, mapsize, sym->st_shndx)) &&
|
||||
(res = getelfstring(elf, mapsize, shstrtab, shdr->sh_name))) ||
|
||||
(strtab && (res = getelfstring(elf, mapsize, strtab, sym->st_name))))) {
|
||||
return res;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void printelfrelocations(void) {
|
||||
int sym;
|
||||
size_t i, j;
|
||||
const Elf64_Sym *syms;
|
||||
const Elf64_Rela *rela;
|
||||
const Elf64_Shdr *shdr, *boop;
|
||||
char *strtab, *shstrtab, *symbolname;
|
||||
strtab = getelfstringtable(elf, st->st_size);
|
||||
shstrtab = getelfsectionnamestringtable(elf, st->st_size);
|
||||
for (i = 0; i < elf->e_shnum; ++i) {
|
||||
if ((shdr = getelfsectionheaderaddress(elf, st->st_size, i)) &&
|
||||
shdr->sh_type == SHT_RELA &&
|
||||
(rela = getelfsectionaddress(elf, st->st_size, shdr))) {
|
||||
printf("\n/\t%s\n", getelfsectionname(elf, st->st_size, shdr));
|
||||
printf("\t.org\t%#x\n", (intptr_t)rela - (intptr_t)elf);
|
||||
for (j = 0; ((uintptr_t)rela + sizeof(Elf64_Rela) <=
|
||||
min((uintptr_t)elf + st->st_size,
|
||||
(uintptr_t)elf + shdr->sh_offset + shdr->sh_size));
|
||||
++rela, ++j) {
|
||||
boop = getelfsectionheaderaddress(elf, st->st_size, shdr->sh_link);
|
||||
syms = getelfsectionaddress(elf, st->st_size, boop);
|
||||
sym = ELF64_R_SYM(rela->r_info);
|
||||
symbolname =
|
||||
getelfsymbolname(elf, st->st_size, strtab, shstrtab, &syms[sym]);
|
||||
printf("/\t%s+%#lx → %s%c%#lx\n",
|
||||
getelfstring(
|
||||
elf, st->st_size, shstrtab,
|
||||
getelfsectionheaderaddress(elf, st->st_size, shdr->sh_info)
|
||||
->sh_name),
|
||||
rela->r_offset, symbolname, rela->r_addend >= 0 ? '+' : '-',
|
||||
abs(rela->r_addend));
|
||||
printf("%s_%zu_%zu:\n", ".Lrela", i, j);
|
||||
show(".quad", format(b1, "%#lx", rela->r_offset), "rela->r_offset");
|
||||
show(".long",
|
||||
format(b1, "%s%s", "R_X86_64_",
|
||||
findnamebyid(kElfNexgen32eRelocationNames,
|
||||
ELF64_R_TYPE(rela->r_info))),
|
||||
"ELF64_R_TYPE(rela->r_info)");
|
||||
show(".long", format(b1, "%d", ELF64_R_SYM(rela->r_info)),
|
||||
|
||||
"ELF64_R_SYM(rela->r_info)");
|
||||
show(".quad", format(b1, "%#lx", rela->r_addend), "rela->r_addend");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
showcrashreports();
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %`s FILE: %s\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
path = argv[1];
|
||||
int64_t fd = open(path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) {
|
||||
fprintf(stderr, "error: %`s not found\n", path);
|
||||
exit(1);
|
||||
}
|
||||
perror("open");
|
||||
exit(1);
|
||||
}
|
||||
fstat(fd, st);
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(elf = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
if (memcmp(elf->e_ident, ELFMAG, 4) != 0) {
|
||||
fprintf(stderr, "error: not an elf executable: %'s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
startfile();
|
||||
printelfehdr();
|
||||
printelfsegmentheaders();
|
||||
printelfsectionheaders();
|
||||
printelfrelocations();
|
||||
printelfsymboltable();
|
||||
munmap(elf, st->st_size);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
267
tool/decode/ent.c
Normal file
267
tool/decode/ent.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
/* PUBLIC DOMAIN */
|
||||
/* clang-format off */
|
||||
/*
|
||||
ENT -- Entropy calculation and analysis of putative
|
||||
random sequences.
|
||||
|
||||
Designed and implemented by John "Random" Walker in May 1985.
|
||||
|
||||
Multiple analyses of random sequences added in December 1985.
|
||||
|
||||
Bit stream analysis added in September 1997.
|
||||
|
||||
Terse mode output, getopt() command line processing,
|
||||
optional stdin input, and HTML documentation added in
|
||||
October 1998.
|
||||
|
||||
Documentation for the -t (terse output) option added
|
||||
in July 2006.
|
||||
|
||||
Replaced table look-up for chi square to probability
|
||||
conversion with algorithmic computation in January 2008.
|
||||
|
||||
For additional information and the latest version,
|
||||
see http://www.fourmilab.ch/random/
|
||||
|
||||
*/
|
||||
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define UPDATE "January 28th, 2008"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#ifdef M_PI
|
||||
#define PI M_PI
|
||||
#else
|
||||
#define PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
/* ISO 8859/1 Latin-1 alphabetic and upper and lower case bit vector tables. */
|
||||
#define isISOspace(x) \
|
||||
((isascii(((unsigned char)(x))) && isspace(((unsigned char)(x)))) || \
|
||||
((x) == 0xA0))
|
||||
#define isISOalpha(x) \
|
||||
((isoalpha[(((unsigned char)(x))) / 8] & \
|
||||
(0x80 >> ((((unsigned char)(x))) % 8))) != 0)
|
||||
#define isISOupper(x) \
|
||||
((isoupper[(((unsigned char)(x))) / 8] & \
|
||||
(0x80 >> ((((unsigned char)(x))) % 8))) != 0)
|
||||
#define isISOlower(x) \
|
||||
((isolower[(((unsigned char)(x))) / 8] & \
|
||||
(0x80 >> ((((unsigned char)(x))) % 8))) != 0)
|
||||
#define isISOprint(x) ((((x) >= ' ') && ((x) <= '~')) || ((x) >= 0xA0))
|
||||
#define toISOupper(x) \
|
||||
(isISOlower(x) \
|
||||
? (isascii(((unsigned char)(x))) ? toupper(x) \
|
||||
: (((((unsigned char)(x)) != 0xDF) && \
|
||||
(((unsigned char)(x)) != 0xFF)) \
|
||||
? (((unsigned char)(x)) - 0x20) \
|
||||
: (x))) \
|
||||
: (x))
|
||||
#define toISOlower(x) \
|
||||
(isISOupper(x) \
|
||||
? (isascii(((unsigned char)(x))) ? tolower(x) \
|
||||
: (((unsigned char)(x)) + 0x20)) \
|
||||
: (x))
|
||||
|
||||
unsigned char isoalpha[32] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 224, 127, 255, 255, 224,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 254, 255, 255, 255, 254, 255};
|
||||
unsigned char isoupper[32] = {0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255,
|
||||
224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 255, 255, 254, 254, 0, 0, 0, 0};
|
||||
unsigned char isolower[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 127, 255, 255, 224, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 255, 255, 254, 255};
|
||||
|
||||
/* HELP -- Print information on how to call */
|
||||
|
||||
static void help(void)
|
||||
{
|
||||
printf("ent -- Calculate entropy of file. Call");
|
||||
printf("\n with ent [options] [input-file]");
|
||||
printf("\n");
|
||||
printf("\n Options: -b Treat input as a stream of bits");
|
||||
printf("\n -c Print occurrence counts");
|
||||
printf("\n -f Fold upper to lower case letters");
|
||||
printf("\n -t Terse output in CSV format");
|
||||
printf("\n -u Print this message\n");
|
||||
printf("\nBy John Walker");
|
||||
printf("\n http://www.fourmilab.ch/");
|
||||
printf("\n %s\n", UPDATE);
|
||||
}
|
||||
|
||||
/* Main program */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, oc, opt;
|
||||
long ccount[256]; /* Bins to count occurrences of values */
|
||||
long totalc = 0; /* Total character count */
|
||||
char *samp;
|
||||
double montepi, chip,
|
||||
scc, ent, mean, chisq;
|
||||
FILE *fp = stdin;
|
||||
int counts = FALSE, /* Print character counts */
|
||||
fold = FALSE, /* Fold upper to lower */
|
||||
binary = FALSE, /* Treat input as a bitstream */
|
||||
terse = FALSE; /* Terse (CSV format) output */
|
||||
|
||||
while ((opt = getopt(argc, argv, "bcftu?BCFTU")) != -1) {
|
||||
switch (toISOlower(opt)) {
|
||||
case 'b':
|
||||
binary = TRUE;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
counts = TRUE;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
fold = TRUE;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
terse = TRUE;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
case 'u':
|
||||
help();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (optind < argc) {
|
||||
if (optind != (argc - 1)) {
|
||||
printf("Duplicate file name.\n");
|
||||
help();
|
||||
return 2;
|
||||
}
|
||||
if ((fp = fopen(argv[optind], "rb")) == NULL) {
|
||||
printf("Cannot open file %s\n", argv[optind]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
samp = binary ? "bit" : "byte";
|
||||
memset(ccount, 0, sizeof ccount);
|
||||
|
||||
/* Initialise for calculations */
|
||||
|
||||
rt_init(binary);
|
||||
|
||||
/* Scan input file and count character occurrences */
|
||||
|
||||
while ((oc = fgetc(fp)) != EOF) {
|
||||
unsigned char ocb;
|
||||
|
||||
if (fold && isISOalpha(oc) && isISOupper(oc)) {
|
||||
oc = toISOlower(oc);
|
||||
}
|
||||
ocb = (unsigned char) oc;
|
||||
totalc += binary ? 8 : 1;
|
||||
if (binary) {
|
||||
int b;
|
||||
unsigned char ob = ocb;
|
||||
|
||||
for (b = 0; b < 8; b++) {
|
||||
ccount[ob & 1]++;
|
||||
ob >>= 1;
|
||||
}
|
||||
} else {
|
||||
ccount[ocb]++; /* Update counter for this bin */
|
||||
}
|
||||
rt_add(&ocb, 1);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
/* Complete calculation and return sequence metrics */
|
||||
|
||||
rt_end(&ent, &chisq, &mean, &montepi, &scc);
|
||||
|
||||
if (terse) {
|
||||
printf("0,File-%ss,Entropy,Chi-square,Mean,Monte-Carlo-Pi,Serial-Correlation\n",
|
||||
binary ? "bit" : "byte");
|
||||
printf("1,%ld,%f,%f,%f,%f,%f\n",
|
||||
totalc, ent, chisq, mean, montepi, scc);
|
||||
}
|
||||
|
||||
/* Calculate probability of observed distribution occurring from
|
||||
the results of the Chi-Square test */
|
||||
|
||||
chip = pochisq(chisq, (binary ? 1 : 255));
|
||||
|
||||
/* Print bin counts if requested */
|
||||
|
||||
if (counts) {
|
||||
if (terse) {
|
||||
printf("2,Value,Occurrences,Fraction\n");
|
||||
} else {
|
||||
printf("Value Char Occurrences Fraction\n");
|
||||
}
|
||||
for (i = 0; i < (binary ? 2 : 256); i++) {
|
||||
if (terse) {
|
||||
printf("3,%d,%ld,%f\n", i,
|
||||
ccount[i], ((double) ccount[i] / totalc));
|
||||
} else {
|
||||
if (ccount[i] > 0) {
|
||||
printf("%3d %c %10ld %f\n", i,
|
||||
/* The following expression shows ISO 8859-1
|
||||
Latin1 characters and blanks out other codes.
|
||||
The test for ISO space replaces the ISO
|
||||
non-blanking space (0xA0) with a regular
|
||||
ASCII space, guaranteeing it's rendered
|
||||
properly even when the font doesn't contain
|
||||
that character, which is the case with many
|
||||
X fonts. */
|
||||
(!isISOprint(i) || isISOspace(i)) ? ' ' : i,
|
||||
ccount[i], ((double) ccount[i] / totalc));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!terse) {
|
||||
printf("\nTotal: %10ld %f\n\n", totalc, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print calculated results */
|
||||
|
||||
if (!terse) {
|
||||
printf("Entropy = %f bits per %s.\n", ent, samp);
|
||||
printf("\nOptimum compression would reduce the size\n");
|
||||
printf("of this %ld %s file by %d percent.\n\n", totalc, samp,
|
||||
(short) ((100 * ((binary ? 1 : 8) - ent) /
|
||||
(binary ? 1.0 : 8.0))));
|
||||
printf(
|
||||
"Chi square distribution for %ld samples is %1.2f, and randomly\n",
|
||||
totalc, chisq);
|
||||
if (chip < 0.0001) {
|
||||
printf("would exceed this value less than 0.01 percent of the times.\n\n");
|
||||
} else if (chip > 0.9999) {
|
||||
printf("would exceed this value more than than 99.99 percent of the times.\n\n");
|
||||
} else {
|
||||
printf("would exceed this value %1.2f percent of the times.\n\n",
|
||||
chip * 100);
|
||||
}
|
||||
printf(
|
||||
"Arithmetic mean value of data %ss is %1.4f (%.1f = random).\n",
|
||||
samp, mean, binary ? 0.5 : 127.5);
|
||||
printf("Monte Carlo value for Pi is %1.9f (error %1.2f percent).\n",
|
||||
montepi, 100.0 * (fabs(PI - montepi) / PI));
|
||||
printf("Serial correlation coefficient is ");
|
||||
if (scc >= -99999) {
|
||||
printf("%1.6f (totally uncorrelated = 0.0).\n", scc);
|
||||
} else {
|
||||
printf("undefined (all values equal!).\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
33
tool/decode/hex.c
Normal file
33
tool/decode/hex.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Binary to hex converter program.
|
||||
*/
|
||||
|
||||
int main() {
|
||||
int o;
|
||||
while (0 <= (o = getchar()) && o <= 255) {
|
||||
putchar("0123456789ABCDEF"[o / 16]);
|
||||
putchar("0123456789ABCDEF"[o % 16]);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
57
tool/decode/lib/asmcodegen.c
Normal file
57
tool/decode/lib/asmcodegen.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/decode/lib/asmcodegen.h"
|
||||
|
||||
char b1[BUFSIZ];
|
||||
char b2[BUFSIZ];
|
||||
|
||||
char *format(char *buf, const char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vsnprintf(buf, BUFSIZ, fmt, va);
|
||||
va_end(va);
|
||||
return buf;
|
||||
}
|
||||
|
||||
nodiscard char *tabpad(const char *s, unsigned width) {
|
||||
char *p;
|
||||
size_t i, l, need;
|
||||
l = strlen(s);
|
||||
need = width > l ? (roundup(width, 8) - l - 1) / 8 + 1 : 0;
|
||||
p = memcpy(malloc(l + need + 1), s, l);
|
||||
for (i = 0; i < need; ++i) p[l + i] = '\t';
|
||||
p[l + need] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
void show(const char *directive, const char *value, const char *comment) {
|
||||
if (comment) {
|
||||
printf("\t%s\t%s# %s\n", directive, gc(tabpad(value, COLUMN_WIDTH)),
|
||||
comment);
|
||||
} else {
|
||||
printf("\t%s\t%s\n", directive, gc(tabpad(value, COLUMN_WIDTH)));
|
||||
}
|
||||
}
|
27
tool/decode/lib/asmcodegen.h
Normal file
27
tool/decode/lib/asmcodegen.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_ASMCODEGEN_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_ASMCODEGEN_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define COLUMN_WIDTH 24
|
||||
|
||||
#define showint(x) show(".long", format(b1, "%d", x), #x)
|
||||
#define showint64(x) show(".quad", format(b1, "%ld", x), #x)
|
||||
#define showbyte(x) show(".byte", format(b1, "%hhn", x), #x)
|
||||
#define showshort(x) show(".short", format(b1, "%hn", x), #x)
|
||||
#define showshorthex(x) show(".short", format(b1, "%#-6hX", x), #x)
|
||||
#define showinthex(x) show(".long", format(b1, "%#X", x), #x)
|
||||
#define showint64hex(x) show(".quad", format(b1, "%#lX", x), #x)
|
||||
#define showorg(x) show(".org", format(b1, "%#lX", x), #x)
|
||||
|
||||
extern char b1[BUFSIZ];
|
||||
extern char b2[BUFSIZ];
|
||||
|
||||
char *format(char *buf, const char *fmt, ...);
|
||||
nodiscard char *tabpad(const char *s, unsigned width);
|
||||
void show(const char *directive, const char *value, const char *comment);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_ASMCODEGEN_H_ */
|
76
tool/decode/lib/bitabuilder.c
Normal file
76
tool/decode/lib/bitabuilder.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/decode/lib/bitabuilder.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Sparse bit array builder.
|
||||
*/
|
||||
|
||||
struct BitaBuilder {
|
||||
size_t i, n;
|
||||
unsigned *p;
|
||||
};
|
||||
|
||||
struct BitaBuilder *bitabuilder_new(void) {
|
||||
return calloc(1, sizeof(struct BitaBuilder));
|
||||
}
|
||||
|
||||
void bitabuilder_free(struct BitaBuilder **bbpp) {
|
||||
if (*bbpp) {
|
||||
free_s(&(*bbpp)->p);
|
||||
free_s(bbpp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets bit.
|
||||
*
|
||||
* @return false if out of memory
|
||||
*/
|
||||
bool bitabuilder_setbit(struct BitaBuilder *bb, size_t bit) {
|
||||
void *p2;
|
||||
size_t i, n;
|
||||
i = MAX(bb->i, ROUNDUP(bit / CHAR_BIT + 1, __BIGGEST_ALIGNMENT__));
|
||||
if (i > bb->n) {
|
||||
n = i + (i >> 2);
|
||||
if ((p2 = realloc(bb->p, n))) {
|
||||
memset((char *)p2 + bb->n, 0, n - bb->n);
|
||||
bb->n = n;
|
||||
bb->p = p2;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bb->i = i;
|
||||
bts(bb->p, bit);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bitabuilder_fwrite(const struct BitaBuilder *bb, FILE *f) {
|
||||
return fwrite(bb->p, bb->i, 1, f);
|
||||
}
|
15
tool/decode/lib/bitabuilder.h
Normal file
15
tool/decode/lib/bitabuilder.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_BITABUILDER_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_BITABUILDER_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct FILE;
|
||||
struct BitaBuilder;
|
||||
struct BitaBuilder *bitabuilder_new(void);
|
||||
bool bitabuilder_setbit(struct BitaBuilder *, size_t);
|
||||
bool bitabuilder_fwrite(const struct BitaBuilder *, struct FILE *);
|
||||
void bitabuilder_free(struct BitaBuilder **);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_BITABUILDER_H_ */
|
62
tool/decode/lib/decodelib.mk
Normal file
62
tool/decode/lib/decodelib.mk
Normal file
|
@ -0,0 +1,62 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_DECODE_LIB
|
||||
|
||||
TOOL_DECODE_LIB_ARTIFACTS += TOOL_DECODE_LIB_A
|
||||
TOOL_DECODE_LIB = $(TOOL_DECODE_LIB_A_DEPS) $(TOOL_DECODE_LIB_A)
|
||||
TOOL_DECODE_LIB_A = o/$(MODE)/tool/decode/lib/decodelib.a
|
||||
TOOL_DECODE_LIB_A_FILES := $(wildcard tool/decode/lib/*)
|
||||
TOOL_DECODE_LIB_A_HDRS = $(filter %.h,$(TOOL_DECODE_LIB_A_FILES))
|
||||
TOOL_DECODE_LIB_A_SRCS_S = $(filter %.S,$(TOOL_DECODE_LIB_A_FILES))
|
||||
TOOL_DECODE_LIB_A_SRCS_C = $(filter %.c,$(TOOL_DECODE_LIB_A_FILES))
|
||||
TOOL_DECODE_LIB_A_CHECKS = $(TOOL_DECODE_LIB_A).pkg
|
||||
|
||||
TOOL_DECODE_LIB_A_SRCS = \
|
||||
$(TOOL_DECODE_LIB_A_SRCS_S) \
|
||||
$(TOOL_DECODE_LIB_A_SRCS_C)
|
||||
|
||||
TOOL_DECODE_LIB_A_OBJS = \
|
||||
$(TOOL_DECODE_LIB_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(TOOL_DECODE_LIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(TOOL_DECODE_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_DECODE_LIB_A_DIRECTDEPS = \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STUBS \
|
||||
LIBC_STR \
|
||||
LIBC_STDIO \
|
||||
LIBC_SYSV \
|
||||
LIBC_UNICODE
|
||||
|
||||
TOOL_DECODE_LIB_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_DECODE_LIB_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(TOOL_DECODE_LIB_A): \
|
||||
tool/decode/lib/ \
|
||||
$(TOOL_DECODE_LIB_A).pkg \
|
||||
$(TOOL_DECODE_LIB_A_OBJS)
|
||||
|
||||
$(TOOL_DECODE_LIB_A).pkg: \
|
||||
$(TOOL_DECODE_LIB_A_OBJS) \
|
||||
$(foreach x,$(TOOL_DECODE_LIB_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
TOOL_DECODE_LIB_LIBS = $(foreach x,$(TOOL_DECODE_LIB_ARTIFACTS),$($(x)))
|
||||
TOOL_DECODE_LIB_SRCS = $(foreach x,$(TOOL_DECODE_LIB_ARTIFACTS),$($(x)_SRCS))
|
||||
TOOL_DECODE_LIB_HDRS = $(foreach x,$(TOOL_DECODE_LIB_ARTIFACTS),$($(x)_HDRS))
|
||||
TOOL_DECODE_LIB_BINS = $(foreach x,$(TOOL_DECODE_LIB_ARTIFACTS),$($(x)_BINS))
|
||||
TOOL_DECODE_LIB_CHECKS = $(foreach x,$(TOOL_DECODE_LIB_ARTIFACTS),$($(x)_CHECKS))
|
||||
TOOL_DECODE_LIB_OBJS = $(foreach x,$(TOOL_DECODE_LIB_ARTIFACTS),$($(x)_OBJS))
|
||||
TOOL_DECODE_LIB_TESTS = $(foreach x,$(TOOL_DECODE_LIB_ARTIFACTS),$($(x)_TESTS))
|
||||
|
||||
o/$(MODE)/tool/decode/lib/elfidnames.o \
|
||||
o/$(MODE)/tool/decode/lib/machoidnames.o \
|
||||
o/$(MODE)/tool/decode/lib/peidnames.o: \
|
||||
DEFAULT_CFLAGS += \
|
||||
-fdata-sections
|
||||
|
||||
.PHONY: o/$(MODE)/tool/decode/lib
|
||||
o/$(MODE)/tool/decode/lib: $(TOOL_DECODE_LIB_CHECKS)
|
60
tool/decode/lib/disassemblehex.c
Normal file
60
tool/decode/lib/disassemblehex.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/decode/lib/disassemblehex.h"
|
||||
|
||||
static size_t countzeroes(const uint8_t *data, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (data[i] != '\0') break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void disassemblehex(uint8_t *data, size_t size, FILE *f) {
|
||||
int col;
|
||||
uint8_t ch;
|
||||
size_t i, z;
|
||||
char16_t glyphs[kDisassembleHexColumns + 1];
|
||||
col = 0;
|
||||
for (i = 0; i < size; ++i) {
|
||||
ch = data[i];
|
||||
if (!col) {
|
||||
z = countzeroes(&data[i], size - i) / kDisassembleHexColumns;
|
||||
if (z > 2) {
|
||||
fprintf(f, "\t.%s\t%zu*%d\n", "zero", z, kDisassembleHexColumns);
|
||||
i += z * kDisassembleHexColumns;
|
||||
if (i == size) break;
|
||||
}
|
||||
fprintf(f, "\t.%s\t", "byte");
|
||||
memset(glyphs, 0, sizeof(glyphs));
|
||||
}
|
||||
/* TODO(jart): Fix Emacs */
|
||||
glyphs[col] = kCp437[ch == '"' || ch == '\\' || ch == '#' ? '.' : ch];
|
||||
if (col) fputc(',', f);
|
||||
fprintf(f, "0x%02x", ch);
|
||||
if (++col == kDisassembleHexColumns) {
|
||||
col = 0;
|
||||
fprintf(f, "\t#%hs\n", glyphs);
|
||||
}
|
||||
}
|
||||
if (col) fputc('\n', f);
|
||||
}
|
13
tool/decode/lib/disassemblehex.h
Normal file
13
tool/decode/lib/disassemblehex.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_DISASSEMBLEHEX_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_DISASSEMBLEHEX_H_
|
||||
|
||||
#define kDisassembleHexColumns 8
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void disassemblehex(uint8_t *data, size_t size, FILE *f);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_DISASSEMBLEHEX_H_ */
|
264
tool/decode/lib/elfidnames.c
Normal file
264
tool/decode/lib/elfidnames.c
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/elf/elf.h"
|
||||
#include "tool/decode/lib/elfidnames.h"
|
||||
|
||||
const struct IdName kElfTypeNames[] = {
|
||||
{ET_NONE, "ET_NONE"},
|
||||
{ET_REL, "ET_REL"},
|
||||
{ET_EXEC, "ET_EXEC"},
|
||||
{ET_DYN, "ET_DYN"},
|
||||
{ET_CORE, "ET_CORE"},
|
||||
{ET_NUM, "ET_NUM"},
|
||||
{ET_LOOS, "ET_LOOS"},
|
||||
{ET_HIOS, "ET_HIOS"},
|
||||
{ET_LOPROC, "ET_LOPROC"},
|
||||
{ET_HIPROC, "ET_HIPROC"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfOsabiNames[] = {
|
||||
{ELFOSABI_NONE, "ELFOSABI_NONE"},
|
||||
{ELFOSABI_SYSV, "ELFOSABI_SYSV"},
|
||||
{ELFOSABI_HPUX, "ELFOSABI_HPUX"},
|
||||
{ELFOSABI_NETBSD, "ELFOSABI_NETBSD"},
|
||||
{ELFOSABI_GNU, "ELFOSABI_GNU"},
|
||||
{ELFOSABI_LINUX, "ELFOSABI_LINUX"},
|
||||
{ELFOSABI_SOLARIS, "ELFOSABI_SOLARIS"},
|
||||
{ELFOSABI_AIX, "ELFOSABI_AIX"},
|
||||
{ELFOSABI_IRIX, "ELFOSABI_IRIX"},
|
||||
{ELFOSABI_FREEBSD, "ELFOSABI_FREEBSD"},
|
||||
{ELFOSABI_TRU64, "ELFOSABI_TRU64"},
|
||||
{ELFOSABI_MODESTO, "ELFOSABI_MODESTO"},
|
||||
{ELFOSABI_OPENBSD, "ELFOSABI_OPENBSD"},
|
||||
{ELFOSABI_ARM, "ELFOSABI_ARM"},
|
||||
{ELFOSABI_STANDALONE, "ELFOSABI_STANDALONE"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfClassNames[] = {
|
||||
{ELFCLASSNONE, "ELFCLASSNONE"},
|
||||
{ELFCLASS32, "ELFCLASS32"},
|
||||
{ELFCLASS64, "ELFCLASS64"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfDataNames[] = {
|
||||
{ELFDATANONE, "ELFDATANONE"},
|
||||
{ELFDATA2LSB, "ELFDATA2LSB"},
|
||||
{ELFDATA2MSB, "ELFDATA2MSB"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfMachineNames[] = {
|
||||
{EM_M32, "EM_M32"},
|
||||
{EM_386, "EM_386"},
|
||||
{EM_S390, "EM_S390"},
|
||||
{EM_ARM, "EM_ARM"},
|
||||
{EM_NEXGEN32E, "EM_NEXGEN32E"},
|
||||
{EM_PDP11, "EM_PDP11"},
|
||||
{EM_CRAYNV2, "EM_CRAYNV2"},
|
||||
{EM_L10M, "EM_L10M"},
|
||||
{EM_K10M, "EM_K10M"},
|
||||
{EM_AARCH64, "EM_AARCH64"},
|
||||
{EM_CUDA, "EM_CUDA"},
|
||||
{EM_Z80, "EM_Z80"},
|
||||
{EM_RISCV, "EM_RISCV"},
|
||||
{EM_BPF, "EM_BPF"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfSegmentTypeNames[] = {
|
||||
{PT_NULL, "PT_NULL"}, /* Program header table entry unused */
|
||||
{PT_LOAD, "PT_LOAD"}, /* Loadable program segment */
|
||||
{PT_DYNAMIC, "PT_DYNAMIC"}, /* Dynamic linking information */
|
||||
{PT_INTERP, "PT_INTERP"}, /* Program interpreter */
|
||||
{PT_NOTE, "PT_NOTE"}, /* Auxiliary information */
|
||||
{PT_SHLIB, "PT_SHLIB"}, /* Reserved */
|
||||
{PT_PHDR, "PT_PHDR"}, /* Entry for header table itself */
|
||||
{PT_TLS, "PT_TLS"}, /* Thread-local storage segment */
|
||||
{PT_NUM, "PT_NUM"}, /* Number of defined types */
|
||||
{PT_LOOS, "PT_LOOS"}, /* Start of OS-specific */
|
||||
{PT_GNU_EH_FRAME, "PT_GNU_EH_FRAME"}, /* GCC .eh_frame_hdr segment */
|
||||
{PT_GNU_STACK, "PT_GNU_STACK"}, /* Indicates stack executability */
|
||||
{PT_GNU_RELRO, "PT_GNU_RELRO"}, /* Read-only after relocation */
|
||||
{PT_LOSUNW, "PT_LOSUNW"}, /* <Reserved for Sun Micrososystems> */
|
||||
{PT_SUNWBSS, "PT_SUNWBSS"}, /* Sun Specific segment */
|
||||
{PT_SUNWSTACK, "PT_SUNWSTACK"}, /* Stack segment */
|
||||
{PT_HISUNW, "PT_HISUNW"}, /* </Reserved for Sun Micrososystems> */
|
||||
{PT_HIOS, "PT_HIOS"}, /* End of OS-specific */
|
||||
{PT_LOPROC, "PT_LOPROC"}, /* Start of processor-specific */
|
||||
{PT_HIPROC, "PT_HIPROC"}, /* End of processor-specific */
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfSectionTypeNames[] = {
|
||||
{SHT_NULL, "SHT_NULL"},
|
||||
{SHT_PROGBITS, "SHT_PROGBITS"},
|
||||
{SHT_SYMTAB, "SHT_SYMTAB"},
|
||||
{SHT_STRTAB, "SHT_STRTAB"},
|
||||
{SHT_RELA, "SHT_RELA"},
|
||||
{SHT_HASH, "SHT_HASH"},
|
||||
{SHT_DYNAMIC, "SHT_DYNAMIC"},
|
||||
{SHT_NOTE, "SHT_NOTE"},
|
||||
{SHT_NOBITS, "SHT_NOBITS"},
|
||||
{SHT_REL, "SHT_REL"},
|
||||
{SHT_SHLIB, "SHT_SHLIB"},
|
||||
{SHT_DYNSYM, "SHT_DYNSYM"},
|
||||
{SHT_INIT_ARRAY, "SHT_INIT_ARRAY"},
|
||||
{SHT_FINI_ARRAY, "SHT_FINI_ARRAY"},
|
||||
{SHT_PREINIT_ARRAY, "SHT_PREINIT_ARRAY"},
|
||||
{SHT_GROUP, "SHT_GROUP"},
|
||||
{SHT_SYMTAB_SHNDX, "SHT_SYMTAB_SHNDX"},
|
||||
{SHT_NUM, "SHT_NUM"},
|
||||
{SHT_LOOS, "SHT_LOOS"},
|
||||
{SHT_GNU_ATTRIBUTES, "SHT_GNU_ATTRIBUTES"},
|
||||
{SHT_GNU_HASH, "SHT_GNU_HASH"},
|
||||
{SHT_GNU_LIBLIST, "SHT_GNU_LIBLIST"},
|
||||
{SHT_CHECKSUM, "SHT_CHECKSUM"},
|
||||
{SHT_LOSUNW, "SHT_LOSUNW"},
|
||||
{SHT_SUNW_move, "SHT_SUNW_move"},
|
||||
{SHT_SUNW_COMDAT, "SHT_SUNW_COMDAT"},
|
||||
{SHT_SUNW_syminfo, "SHT_SUNW_syminfo"},
|
||||
{SHT_GNU_verdef, "SHT_GNU_verdef"},
|
||||
{SHT_GNU_verneed, "SHT_GNU_verneed"},
|
||||
{SHT_GNU_versym, "SHT_GNU_versym"},
|
||||
{SHT_HISUNW, "SHT_HISUNW"},
|
||||
{SHT_HIOS, "SHT_HIOS"},
|
||||
{SHT_LOPROC, "SHT_LOPROC"},
|
||||
{SHT_HIPROC, "SHT_HIPROC"},
|
||||
{SHT_LOUSER, "SHT_LOUSER"},
|
||||
{SHT_HIUSER, "SHT_HIUSER"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfSegmentFlagNames[] = {
|
||||
{PF_X, "PF_X"},
|
||||
{PF_W, "PF_W"},
|
||||
{PF_R, "PF_R"},
|
||||
{PF_MASKOS, "PF_MASKOS"},
|
||||
{PF_MASKPROC, "PF_MASKPROC"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfSectionFlagNames[] = {
|
||||
{SHF_WRITE, "SHF_WRITE"},
|
||||
{SHF_ALLOC, "SHF_ALLOC"},
|
||||
{SHF_EXECINSTR, "SHF_EXECINSTR"},
|
||||
{SHF_MERGE, "SHF_MERGE"},
|
||||
{SHF_STRINGS, "SHF_STRINGS"},
|
||||
{SHF_INFO_LINK, "SHF_INFO_LINK"},
|
||||
{SHF_LINK_ORDER, "SHF_LINK_ORDER"},
|
||||
{SHF_OS_NONCONFORMING, "SHF_OS_NONCONFORMING"},
|
||||
{SHF_GROUP, "SHF_GROUP"},
|
||||
{SHF_TLS, "SHF_TLS"},
|
||||
{SHF_COMPRESSED, "SHF_COMPRESSED"},
|
||||
{SHF_MASKOS, "SHF_MASKOS"},
|
||||
{SHF_MASKPROC, "SHF_MASKPROC"},
|
||||
{SHF_ORDERED, "SHF_ORDERED"},
|
||||
{SHF_EXCLUDE, "SHF_EXCLUDE"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfSymbolTypeNames[] = {
|
||||
{STT_NOTYPE, "STT_NOTYPE"}, {STT_OBJECT, "STT_OBJECT"},
|
||||
{STT_FUNC, "STT_FUNC"}, {STT_SECTION, "STT_SECTION"},
|
||||
{STT_FILE, "STT_FILE"}, {STT_COMMON, "STT_COMMON"},
|
||||
{STT_TLS, "STT_TLS"}, {STT_NUM, "STT_NUM"},
|
||||
{STT_LOOS, "STT_LOOS"}, {STT_GNU_IFUNC, "STT_GNU_IFUNC"},
|
||||
{STT_HIOS, "STT_HIOS"}, {STT_LOPROC, "STT_LOPROC"},
|
||||
{STT_HIPROC, "STT_HIPROC"}, {0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfSymbolBindNames[] = {
|
||||
{STB_LOCAL, "STB_LOCAL"}, {STB_GLOBAL, "STB_GLOBAL"},
|
||||
{STB_WEAK, "STB_WEAK"}, {STB_NUM, "STB_NUM"},
|
||||
{STB_LOOS, "STB_LOOS"}, {STB_GNU_UNIQUE, "STB_GNU_UNIQUE"},
|
||||
{STB_HIOS, "STB_HIOS"}, {STB_LOPROC, "STB_LOPROC"},
|
||||
{STB_HIPROC, "STB_HIPROC"}, {0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfSymbolVisibilityNames[] = {
|
||||
{STV_DEFAULT, "STV_DEFAULT"},
|
||||
{STV_INTERNAL, "STV_INTERNAL"},
|
||||
{STV_HIDDEN, "STV_HIDDEN"},
|
||||
{STV_PROTECTED, "STV_PROTECTED"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfSpecialSectionNames[] = {
|
||||
{SHN_UNDEF, "SHN_UNDEF"},
|
||||
{SHN_LORESERVE, "SHN_LORESERVE"},
|
||||
{SHN_LOPROC, "SHN_LOPROC"},
|
||||
{SHN_BEFORE, "SHN_BEFORE"},
|
||||
{SHN_AFTER, "SHN_AFTER"},
|
||||
{SHN_HIPROC, "SHN_HIPROC"},
|
||||
{SHN_LOOS, "SHN_LOOS"},
|
||||
{SHN_HIOS, "SHN_HIOS"},
|
||||
{SHN_ABS, "SHN_ABS"},
|
||||
{SHN_COMMON, "SHN_COMMON"},
|
||||
{SHN_XINDEX, "SHN_XINDEX"},
|
||||
{SHN_HIRESERVE, "SHN_HIRESERVE"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kElfNexgen32eRelocationNames[] = {
|
||||
{R_X86_64_64, "64"},
|
||||
{R_X86_64_PC32, "PC32"},
|
||||
{R_X86_64_GOT32, "GOT32"},
|
||||
{R_X86_64_PLT32, "PLT32"},
|
||||
{R_X86_64_COPY, "COPY"},
|
||||
{R_X86_64_GLOB_DAT, "GLOB_DAT"},
|
||||
{R_X86_64_JUMP_SLOT, "JUMP_SLOT"},
|
||||
{R_X86_64_RELATIVE, "RELATIVE"},
|
||||
{R_X86_64_GOTPCREL, "GOTPCREL"},
|
||||
{R_X86_64_32, "32"},
|
||||
{R_X86_64_32S, "32S"},
|
||||
{R_X86_64_16, "16"},
|
||||
{R_X86_64_PC16, "PC16"},
|
||||
{R_X86_64_8, "8"},
|
||||
{R_X86_64_PC8, "PC8"},
|
||||
{R_X86_64_DTPMOD64, "DTPMOD64"},
|
||||
{R_X86_64_DTPOFF64, "DTPOFF64"},
|
||||
{R_X86_64_TPOFF64, "TPOFF64"},
|
||||
{R_X86_64_TLSGD, "TLSGD"},
|
||||
{R_X86_64_TLSLD, "TLSLD"},
|
||||
{R_X86_64_DTPOFF32, "DTPOFF32"},
|
||||
{R_X86_64_GOTTPOFF, "GOTTPOFF"},
|
||||
{R_X86_64_TPOFF32, "TPOFF32"},
|
||||
{R_X86_64_PC64, "PC64"},
|
||||
{R_X86_64_GOTOFF64, "GOTOFF64"},
|
||||
{R_X86_64_GOTPC32, "GOTPC32"},
|
||||
{R_X86_64_GOT64, "GOT64"},
|
||||
{R_X86_64_GOTPCREL64, "GOTPCREL64"},
|
||||
{R_X86_64_GOTPC64, "GOTPC64"},
|
||||
{R_X86_64_GOTPLT64, "GOTPLT64"},
|
||||
{R_X86_64_PLTOFF64, "PLTOFF64"},
|
||||
{R_X86_64_SIZE32, "SIZE32"},
|
||||
{R_X86_64_SIZE64, "SIZE64"},
|
||||
{R_X86_64_GOTPC32_TLSDESC, "GOTPC32_TLSDESC"},
|
||||
{R_X86_64_TLSDESC_CALL, "TLSDESC_CALL"},
|
||||
{R_X86_64_TLSDESC, "TLSDESC"},
|
||||
{R_X86_64_IRELATIVE, "IRELATIVE"},
|
||||
{R_X86_64_RELATIVE64, "RELATIVE64"},
|
||||
{R_X86_64_GOTPCRELX, "GOTPCRELX"},
|
||||
{R_X86_64_REX_GOTPCRELX, "REX_GOTPCRELX"},
|
||||
{0, 0},
|
||||
};
|
24
tool/decode/lib/elfidnames.h
Normal file
24
tool/decode/lib/elfidnames.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_ELFIDNAMES_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_ELFIDNAMES_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const struct IdName kElfTypeNames[];
|
||||
extern const struct IdName kElfOsabiNames[];
|
||||
extern const struct IdName kElfClassNames[];
|
||||
extern const struct IdName kElfDataNames[];
|
||||
extern const struct IdName kElfMachineNames[];
|
||||
extern const struct IdName kElfSegmentTypeNames[];
|
||||
extern const struct IdName kElfSectionTypeNames[];
|
||||
extern const struct IdName kElfSegmentFlagNames[];
|
||||
extern const struct IdName kElfSectionFlagNames[];
|
||||
extern const struct IdName kElfSymbolTypeNames[];
|
||||
extern const struct IdName kElfSymbolBindNames[];
|
||||
extern const struct IdName kElfSymbolVisibilityNames[];
|
||||
extern const struct IdName kElfSpecialSectionNames[];
|
||||
extern const struct IdName kElfNexgen32eRelocationNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_ELFIDNAMES_H_ */
|
62
tool/decode/lib/flagger.c
Normal file
62
tool/decode/lib/flagger.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/decode/lib/flagger.h"
|
||||
|
||||
struct FlagNameBuf {
|
||||
size_t i, n;
|
||||
char *p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats numeric flags integer as symbolic code.
|
||||
*
|
||||
* @param names maps individual flags to string names in no order
|
||||
* @param id is the flags
|
||||
* @return NUL-terminated string that needs free()
|
||||
*/
|
||||
nodiscard char *recreateflags(const struct IdName *names, unsigned long id) {
|
||||
struct FlagNameBuf buf = {};
|
||||
char extrabuf[20];
|
||||
bool first;
|
||||
first = true;
|
||||
for (; names->name; names++) {
|
||||
if ((id == 0 && names->id == 0) ||
|
||||
(id != 0 && names->id != 0 && (id & names->id) == names->id)) {
|
||||
id &= ~names->id;
|
||||
if (!first) {
|
||||
append(&buf, "|");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
concat(&buf, names->name, strlen(names->name));
|
||||
}
|
||||
}
|
||||
if (id) {
|
||||
if (buf.i) append(&buf, "|");
|
||||
concat(&buf, extrabuf, snprintf(extrabuf, sizeof(extrabuf), "%#x", id));
|
||||
} else if (!buf.i) {
|
||||
append(&buf, "0");
|
||||
}
|
||||
return buf.p;
|
||||
}
|
11
tool/decode/lib/flagger.h
Normal file
11
tool/decode/lib/flagger.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_FLAGGER_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_FLAGGER_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
char *recreateflags(const struct IdName *, unsigned long) nodiscard;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_FLAGGER_H_ */
|
29
tool/decode/lib/idname.c
Normal file
29
tool/decode/lib/idname.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/decode/lib/idname.h"
|
||||
|
||||
const char *findnamebyid(const struct IdName *names, unsigned long id) {
|
||||
for (; names->name; names++) {
|
||||
if (names->id == id) {
|
||||
return names->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
15
tool/decode/lib/idname.h
Normal file
15
tool/decode/lib/idname.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_IDNAME_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_IDNAME_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct IdName {
|
||||
unsigned long id;
|
||||
const char *const name;
|
||||
};
|
||||
|
||||
const char *findnamebyid(const struct IdName *names, unsigned long id);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_IDNAME_H_ */
|
150
tool/decode/lib/machoidnames.c
Normal file
150
tool/decode/lib/machoidnames.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macho.h"
|
||||
#include "tool/decode/lib/machoidnames.h"
|
||||
|
||||
const struct IdName kMachoFileTypeNames[] = {
|
||||
{MAC_OBJECT, "MAC_OBJECT"},
|
||||
{MAC_EXECUTE, "MAC_EXECUTE"},
|
||||
{MAC_FVMLIB, "MAC_FVMLIB"},
|
||||
{MAC_CORE, "MAC_CORE"},
|
||||
{MAC_PRELOAD, "MAC_PRELOAD"},
|
||||
{MAC_DYLIB, "MAC_DYLIB"},
|
||||
{MAC_DYLINKER, "MAC_DYLINKER"},
|
||||
{MAC_BUNDLE, "MAC_BUNDLE"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kMachoFlagNames[] = {
|
||||
{MAC_NOUNDEFS, "MAC_NOUNDEFS"},
|
||||
{MAC_INCRLINK, "MAC_INCRLINK"},
|
||||
{MAC_DYLDLINK, "MAC_DYLDLINK"},
|
||||
{MAC_BINDATLOAD, "MAC_BINDATLOAD"},
|
||||
{MAC_PREBOUND, "MAC_PREBOUND"},
|
||||
{MAC_SPLIT_SEGS, "MAC_SPLIT_SEGS"},
|
||||
{MAC_LAZY_INIT, "MAC_LAZY_INIT"},
|
||||
{MAC_TWOLEVEL, "MAC_TWOLEVEL"},
|
||||
{MAC_FORCE_FLAT, "MAC_FORCE_FLAT"},
|
||||
{MAC_NOMULTIDEFS, "MAC_NOMULTIDEFS"},
|
||||
{MAC_NOFIXPREBINDING, "MAC_NOFIXPREBINDING"},
|
||||
{MAC_PREBINDABLE, "MAC_PREBINDABLE"},
|
||||
{MAC_ALLMODSBOUND, "MAC_ALLMODSBOUND"},
|
||||
{MAC_SUBSECTIONS_VIA_SYMBOLS, "MAC_SUBSECTIONS_VIA_SYMBOLS"},
|
||||
{MAC_CANONICAL, "MAC_CANONICAL"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kMachoSegmentFlagNames[] = {
|
||||
{MAC_SG_HIGHVM, "MAC_SG_HIGHVM"},
|
||||
{MAC_SG_FVMLIB, "MAC_SG_FVMLIB"},
|
||||
{MAC_SG_NORELOC, "MAC_SG_NORELOC"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kMachoSectionTypeNames[] = {
|
||||
{MAC_S_REGULAR, "MAC_S_REGULAR"},
|
||||
{MAC_S_ZEROFILL, "MAC_S_ZEROFILL"},
|
||||
{MAC_S_CSTRING_LITERALS, "MAC_S_CSTRING_LITERALS"},
|
||||
{MAC_S_4BYTE_LITERALS, "MAC_S_4BYTE_LITERALS"},
|
||||
{MAC_S_8BYTE_LITERALS, "MAC_S_8BYTE_LITERALS"},
|
||||
{MAC_S_LITERAL_POINTERS, "MAC_S_LITERAL_POINTERS"},
|
||||
{MAC_S_NON_LAZY_SYMBOL_POINTERS, "MAC_S_NON_LAZY_SYMBOL_POINTERS"},
|
||||
{MAC_S_LAZY_SYMBOL_POINTERS, "MAC_S_LAZY_SYMBOL_POINTERS"},
|
||||
{MAC_S_SYMBOL_STUBS, "MAC_S_SYMBOL_STUBS"},
|
||||
{MAC_S_MOD_INIT_FUNC_POINTERS, "MAC_S_MOD_INIT_FUNC_POINTERS"},
|
||||
{MAC_S_MOD_TERM_FUNC_POINTERS, "MAC_S_MOD_TERM_FUNC_POINTERS"},
|
||||
{MAC_S_COALESCED, "MAC_S_COALESCED"},
|
||||
{MAC_S_GB_ZEROFILL, "MAC_S_GB_ZEROFILL"},
|
||||
{MAC_S_INTERPOSING, "MAC_S_INTERPOSING"},
|
||||
{MAC_S_16BYTE_LITERALS, "MAC_S_16BYTE_LITERALS"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kMachoSectionAttributeNames[] = {
|
||||
{MAC_SECTION_ATTRIBUTES_USR, "MAC_SECTION_ATTRIBUTES_USR"},
|
||||
{MAC_S_ATTR_PURE_INSTRUCTIONS, "MAC_S_ATTR_PURE_INSTRUCTIONS"},
|
||||
{MAC_S_ATTR_NO_TOC, "MAC_S_ATTR_NO_TOC"},
|
||||
{MAC_S_ATTR_STRIP_STATIC_SYMS, "MAC_S_ATTR_STRIP_STATIC_SYMS"},
|
||||
{MAC_S_ATTR_NO_DEAD_STRIP, "MAC_S_ATTR_NO_DEAD_STRIP"},
|
||||
{MAC_S_ATTR_LIVE_SUPPORT, "MAC_S_ATTR_LIVE_SUPPORT"},
|
||||
{MAC_S_ATTR_SELF_MODIFYING_CODE, "MAC_S_ATTR_SELF_MODIFYING_CODE"},
|
||||
{MAC_S_ATTR_DEBUG, "MAC_S_ATTR_DEBUG"},
|
||||
{MAC_SECTION_ATTRIBUTES_SYS, "MAC_SECTION_ATTRIBUTES_SYS"},
|
||||
{MAC_S_ATTR_SOME_INSTRUCTIONS, "MAC_S_ATTR_SOME_INSTRUCTIONS"},
|
||||
{MAC_S_ATTR_EXT_RELOC, "MAC_S_ATTR_EXT_RELOC"},
|
||||
{MAC_S_ATTR_LOC_RELOC, "MAC_S_ATTR_LOC_RELOC"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kMachoLoadCommandNames[] = {
|
||||
{MAC_LC_REQ_DYLD, "MAC_LC_REQ_DYLD"},
|
||||
{MAC_LC_SEGMENT, "MAC_LC_SEGMENT"},
|
||||
{MAC_LC_SYMTAB, "MAC_LC_SYMTAB"},
|
||||
{MAC_LC_SYMSEG, "MAC_LC_SYMSEG"},
|
||||
{MAC_LC_THREAD, "MAC_LC_THREAD"},
|
||||
{MAC_LC_UNIXTHREAD, "MAC_LC_UNIXTHREAD"},
|
||||
{MAC_LC_LOADFVMLIB, "MAC_LC_LOADFVMLIB"},
|
||||
{MAC_LC_IDFVMLIB, "MAC_LC_IDFVMLIB"},
|
||||
{MAC_LC_IDENT, "MAC_LC_IDENT"},
|
||||
{MAC_LC_FVMFILE, "MAC_LC_FVMFILE"},
|
||||
{MAC_LC_PREPAGE, "MAC_LC_PREPAGE"},
|
||||
{MAC_LC_DYSYMTAB, "MAC_LC_DYSYMTAB"},
|
||||
{MAC_LC_LOAD_DYLIB, "MAC_LC_LOAD_DYLIB"},
|
||||
{MAC_LC_ID_DYLIB, "MAC_LC_ID_DYLIB"},
|
||||
{MAC_LC_LOAD_DYLINKER, "MAC_LC_LOAD_DYLINKER"},
|
||||
{MAC_LC_ID_DYLINKER, "MAC_LC_ID_DYLINKER"},
|
||||
{MAC_LC_PREBOUND_DYLIB, "MAC_LC_PREBOUND_DYLIB"},
|
||||
{MAC_LC_ROUTINES, "MAC_LC_ROUTINES"},
|
||||
{MAC_LC_SUB_FRAMEWORK, "MAC_LC_SUB_FRAMEWORK"},
|
||||
{MAC_LC_SUB_UMBRELLA, "MAC_LC_SUB_UMBRELLA"},
|
||||
{MAC_LC_SUB_CLIENT, "MAC_LC_SUB_CLIENT"},
|
||||
{MAC_LC_SUB_LIBRARY, "MAC_LC_SUB_LIBRARY"},
|
||||
{MAC_LC_TWOLEVEL_HINTS, "MAC_LC_TWOLEVEL_HINTS"},
|
||||
{MAC_LC_PREBIND_CKSUM, "MAC_LC_PREBIND_CKSUM"},
|
||||
{MAC_LC_LOAD_WEAK_DYLIB, "MAC_LC_LOAD_WEAK_DYLIB"},
|
||||
{MAC_LC_SEGMENT_64, "MAC_LC_SEGMENT_64"},
|
||||
{MAC_LC_ROUTINES_64, "MAC_LC_ROUTINES_64"},
|
||||
{MAC_LC_UUID, "MAC_LC_UUID"},
|
||||
{MAC_LC_CODE_SIGNATURE, "MAC_LC_CODE_SIGNATURE"},
|
||||
{MAC_LC_SEGMENT_SPLIT_INFO, "MAC_LC_SEGMENT_SPLIT_INFO"},
|
||||
{MAC_LC_LAZY_LOAD_DYLIB, "MAC_LC_LAZY_LOAD_DYLIB"},
|
||||
{MAC_LC_ENCRYPTION_INFO, "MAC_LC_ENCRYPTION_INFO"},
|
||||
{MAC_LC_DYLD_INFO, "MAC_LC_DYLD_INFO"},
|
||||
{MAC_LC_VERSION_MIN_MACOSX, "MAC_LC_VERSION_MIN_MACOSX"},
|
||||
{MAC_LC_VERSION_MIN_IPHONEOS, "MAC_LC_VERSION_MIN_IPHONEOS"},
|
||||
{MAC_LC_FUNCTION_STARTS, "MAC_LC_FUNCTION_STARTS"},
|
||||
{MAC_LC_DYLD_ENVIRONMENT, "MAC_LC_DYLD_ENVIRONMENT"},
|
||||
{MAC_LC_DATA_IN_CODE, "MAC_LC_DATA_IN_CODE"},
|
||||
{MAC_LC_SOURCE_VERSION, "MAC_LC_SOURCE_VERSION"},
|
||||
{MAC_LC_RPATH, "MAC_LC_RPATH"},
|
||||
{MAC_LC_MAIN, "MAC_LC_MAIN"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kMachoVmProtNames[] = {
|
||||
{VM_PROT_READ, "VM_PROT_READ"},
|
||||
{VM_PROT_WRITE, "VM_PROT_WRITE"},
|
||||
{VM_PROT_EXECUTE, "VM_PROT_EXECUTE"},
|
||||
{VM_PROT_NO_CHANGE, "VM_PROT_NO_CHANGE"},
|
||||
{VM_PROT_COPY, "VM_PROT_COPY"},
|
||||
{VM_PROT_TRUSTED, "VM_PROT_TRUSTED"},
|
||||
{VM_PROT_STRIP_READ, "VM_PROT_STRIP_READ"},
|
||||
{0, 0},
|
||||
};
|
17
tool/decode/lib/machoidnames.h
Normal file
17
tool/decode/lib/machoidnames.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_MACHOIDNAMES_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_MACHOIDNAMES_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const struct IdName kMachoFileTypeNames[];
|
||||
extern const struct IdName kMachoFlagNames[];
|
||||
extern const struct IdName kMachoSegmentFlagNames[];
|
||||
extern const struct IdName kMachoSectionTypeNames[];
|
||||
extern const struct IdName kMachoSectionAttributeNames[];
|
||||
extern const struct IdName kMachoLoadCommandNames[];
|
||||
extern const struct IdName kMachoVmProtNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_MACHOIDNAMES_H_ */
|
51
tool/decode/lib/ntfileflagnames.c
Normal file
51
tool/decode/lib/ntfileflagnames.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "tool/decode/lib/ntfileflagnames.h"
|
||||
|
||||
const struct IdName kNtFileFlagNames[] = {
|
||||
{kNtFileAttributeReadonly, "kNtFileAttributeReadonly"},
|
||||
{kNtFileAttributeHidden, "kNtFileAttributeHidden"},
|
||||
{kNtFileAttributeSystem, "kNtFileAttributeSystem"},
|
||||
{kNtFileAttributeVolumelabel, "kNtFileAttributeVolumelabel"},
|
||||
{kNtFileAttributeDirectory, "kNtFileAttributeDirectory"},
|
||||
{kNtFileAttributeArchive, "kNtFileAttributeArchive"},
|
||||
{kNtFileAttributeDevice, "kNtFileAttributeDevice"},
|
||||
{kNtFileAttributeNormal, "kNtFileAttributeNormal"},
|
||||
{kNtFileAttributeTemporary, "kNtFileAttributeTemporary"},
|
||||
{kNtFileAttributeSparseFile, "kNtFileAttributeSparseFile"},
|
||||
{kNtFileAttributeReparsePoint, "kNtFileAttributeReparsePoint"},
|
||||
{kNtFileAttributeCompressed, "kNtFileAttributeCompressed"},
|
||||
{kNtFileAttributeOffline, "kNtFileAttributeOffline"},
|
||||
{kNtFileAttributeNotContentIndexed, "kNtFileAttributeNotContentIndexed"},
|
||||
{kNtFileAttributeEncrypted, "kNtFileAttributeEncrypted"},
|
||||
{kNtFileFlagWriteThrough, "kNtFileFlagWriteThrough"},
|
||||
{kNtFileFlagOverlapped, "kNtFileFlagOverlapped"},
|
||||
{kNtFileFlagNoBuffering, "kNtFileFlagNoBuffering"},
|
||||
{kNtFileFlagRandomAccess, "kNtFileFlagRandomAccess"},
|
||||
{kNtFileFlagSequentialScan, "kNtFileFlagSequentialScan"},
|
||||
{kNtFileFlagDeleteOnClose, "kNtFileFlagDeleteOnClose"},
|
||||
{kNtFileFlagBackupSemantics, "kNtFileFlagBackupSemantics"},
|
||||
{kNtFileFlagPosixSemantics, "kNtFileFlagPosixSemantics"},
|
||||
{kNtFileFlagOpenReparsePoint, "kNtFileFlagOpenReparsePoint"},
|
||||
{kNtFileFlagOpenNoRecall, "kNtFileFlagOpenNoRecall"},
|
||||
{kNtFileFlagFirstPipeInstance, "kNtFileFlagFirstPipeInstance"},
|
||||
{0, 0},
|
||||
};
|
11
tool/decode/lib/ntfileflagnames.h
Normal file
11
tool/decode/lib/ntfileflagnames.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_NTFILEFLAGNAMES_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_NTFILEFLAGNAMES_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const struct IdName kNtFileFlagNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_NTFILEFLAGNAMES_H_ */
|
179
tool/decode/lib/peidnames.c
Normal file
179
tool/decode/lib/peidnames.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/pe.h"
|
||||
#include "tool/decode/lib/peidnames.h"
|
||||
|
||||
const struct IdName kNtImageFileMachineNames[] = {
|
||||
{kNtImageFileMachineUnknown, "kNtImageFileMachineUnknown"},
|
||||
{kNtImageFileMachineTargetHost, "kNtImageFileMachineTargetHost"},
|
||||
{kNtImageFileMachineI386, "kNtImageFileMachineI386"},
|
||||
{kNtImageFileMachineR3000, "kNtImageFileMachineR3000"},
|
||||
{kNtImageFileMachineR4000, "kNtImageFileMachineR4000"},
|
||||
{kNtImageFileMachineR10000, "kNtImageFileMachineR10000"},
|
||||
{kNtImageFileMachineWcemipsv2, "kNtImageFileMachineWcemipsv2"},
|
||||
{kNtImageFileMachineAlpha, "kNtImageFileMachineAlpha"},
|
||||
{kNtImageFileMachineSh3, "kNtImageFileMachineSh3"},
|
||||
{kNtImageFileMachineSh3dsp, "kNtImageFileMachineSh3dsp"},
|
||||
{kNtImageFileMachineSh3e, "kNtImageFileMachineSh3e"},
|
||||
{kNtImageFileMachineSh4, "kNtImageFileMachineSh4"},
|
||||
{kNtImageFileMachineSh5, "kNtImageFileMachineSh5"},
|
||||
{kNtImageFileMachineArm, "kNtImageFileMachineArm"},
|
||||
{kNtImageFileMachineThumb, "kNtImageFileMachineThumb"},
|
||||
{kNtImageFileMachineArmnt, "kNtImageFileMachineArmnt"},
|
||||
{kNtImageFileMachineAm33, "kNtImageFileMachineAm33"},
|
||||
{kNtImageFileMachinePowerpc, "kNtImageFileMachinePowerpc"},
|
||||
{kNtImageFileMachinePowerpcfp, "kNtImageFileMachinePowerpcfp"},
|
||||
{kNtImageFileMachineIa64, "kNtImageFileMachineIa64"},
|
||||
{kNtImageFileMachineMips16, "kNtImageFileMachineMips16"},
|
||||
{kNtImageFileMachineAlpha64, "kNtImageFileMachineAlpha64"},
|
||||
{kNtImageFileMachineMipsfpu, "kNtImageFileMachineMipsfpu"},
|
||||
{kNtImageFileMachineMipsfpu16, "kNtImageFileMachineMipsfpu16"},
|
||||
{kNtImageFileMachineAxp64, "kNtImageFileMachineAxp64"},
|
||||
{kNtImageFileMachineTricore, "kNtImageFileMachineTricore"},
|
||||
{kNtImageFileMachineCef, "kNtImageFileMachineCef"},
|
||||
{kNtImageFileMachineEbc, "kNtImageFileMachineEbc"},
|
||||
{kNtImageFileMachineNexgen32e, "kNtImageFileMachineNexgen32e"},
|
||||
{kNtImageFileMachineM32r, "kNtImageFileMachineM32r"},
|
||||
{kNtImageFileMachineArm64, "kNtImageFileMachineArm64"},
|
||||
{kNtImageFileMachineCee, "kNtImageFileMachineCee"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kNtPeOptionalHeaderMagicNames[] = {
|
||||
{kNtPe32bit, "kNtPe32bit"},
|
||||
{kNtPe64bit, "kNtPe64bit"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kNtImageDllcharacteristicNames[] = {
|
||||
{kNtImageDllcharacteristicsHighEntropyVa,
|
||||
"kNtImageDllcharacteristicsHighEntropyVa"},
|
||||
{kNtImageDllcharacteristicsDynamicBase,
|
||||
"kNtImageDllcharacteristicsDynamicBase"},
|
||||
{kNtImageDllcharacteristicsForceIntegrity,
|
||||
"kNtImageDllcharacteristicsForceIntegrity"},
|
||||
{kNtImageDllcharacteristicsNxCompat, "kNtImageDllcharacteristicsNxCompat"},
|
||||
{kNtImageDllcharacteristicsNoIsolation,
|
||||
"kNtImageDllcharacteristicsNoIsolation"},
|
||||
{kNtImageDllcharacteristicsNoSeh, "kNtImageDllcharacteristicsNoSeh"},
|
||||
{kNtImageDllcharacteristicsNoBind, "kNtImageDllcharacteristicsNoBind"},
|
||||
{kNtImageDllcharacteristicsAppcontainer,
|
||||
"kNtImageDllcharacteristicsAppcontainer"},
|
||||
{kNtImageDllcharacteristicsWdmDriver,
|
||||
"kNtImageDllcharacteristicsWdmDriver"},
|
||||
{kNtImageDllcharacteristicsGuardCf, "kNtImageDllcharacteristicsGuardCf"},
|
||||
{kNtImageDllcharacteristicsTerminalServerAware,
|
||||
"kNtImageDllcharacteristicsTerminalServerAware"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kNtImageSubsystemNames[] = {
|
||||
{kNtImageSubsystemUnknown, "kNtImageSubsystemUnknown"},
|
||||
{kNtImageSubsystemNative, "kNtImageSubsystemNative"},
|
||||
{kNtImageSubsystemWindowsGui, "kNtImageSubsystemWindowsGui"},
|
||||
{kNtImageSubsystemWindowsCui, "kNtImageSubsystemWindowsCui"},
|
||||
{kNtImageSubsystemOs2Cui, "kNtImageSubsystemOs2Cui"},
|
||||
{kNtImageSubsystemPosixCui, "kNtImageSubsystemPosixCui"},
|
||||
{kNtImageSubsystemNativeWindows, "kNtImageSubsystemNativeWindows"},
|
||||
{kNtImageSubsystemWindowsCeGui, "kNtImageSubsystemWindowsCeGui"},
|
||||
{kNtImageSubsystemEfiApplication, "kNtImageSubsystemEfiApplication"},
|
||||
{kNtImageSubsystemEfiBootServiceDriver,
|
||||
"kNtImageSubsystemEfiBootServiceDriver"},
|
||||
{kNtImageSubsystemEfiRuntimeDriver, "kNtImageSubsystemEfiRuntimeDriver"},
|
||||
{kNtImageSubsystemEfiRom, "kNtImageSubsystemEfiRom"},
|
||||
{kNtImageSubsystemXbox, "kNtImageSubsystemXbox"},
|
||||
{kNtImageSubsystemWindowsBootApplication,
|
||||
"kNtImageSubsystemWindowsBootApplication"},
|
||||
{kNtImageSubsystemXboxCodeCatalog, "kNtImageSubsystemXboxCodeCatalog"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kNtImageScnNames[] = {
|
||||
{kNtImageScnTypeNoPad, "kNtImageScnTypeNoPad"},
|
||||
{kNtImageScnCntCode, "kNtImageScnCntCode"},
|
||||
{kNtImageScnCntInitializedData, "kNtImageScnCntInitializedData"},
|
||||
{kNtImageScnCntUninitializedData, "kNtImageScnCntUninitializedData"},
|
||||
{kNtImageScnLnkOther, "kNtImageScnLnkOther"},
|
||||
{kNtImageScnLnkInfo, "kNtImageScnLnkInfo"},
|
||||
{kNtImageScnLnkRemove, "kNtImageScnLnkRemove"},
|
||||
{kNtImageScnLnkComdat, "kNtImageScnLnkComdat"},
|
||||
{kNtImageScnNoDeferSpecExc, "kNtImageScnNoDeferSpecExc"},
|
||||
{kNtImageScnGprel, "kNtImageScnGprel"},
|
||||
{kNtImageScnMemFardata, "kNtImageScnMemFardata"},
|
||||
{kNtImageScnMemPurgeable, "kNtImageScnMemPurgeable"},
|
||||
{kNtImageScnMem16bit, "kNtImageScnMem16bit"},
|
||||
{kNtImageScnMemLocked, "kNtImageScnMemLocked"},
|
||||
{kNtImageScnMemPreload, "kNtImageScnMemPreload"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kNtImageDirectoryEntryNames[] = {
|
||||
{kNtImageDirectoryEntryExport, "kNtImageDirectoryEntryExport"},
|
||||
{kNtImageDirectoryEntryImport, "kNtImageDirectoryEntryImport"},
|
||||
{kNtImageDirectoryEntryResource, "kNtImageDirectoryEntryResource"},
|
||||
{kNtImageDirectoryEntryException, "kNtImageDirectoryEntryException"},
|
||||
{kNtImageDirectoryEntrySecurity, "kNtImageDirectoryEntrySecurity"},
|
||||
{kNtImageDirectoryEntryBasereloc, "kNtImageDirectoryEntryBasereloc"},
|
||||
{kNtImageDirectoryEntryDebug, "kNtImageDirectoryEntryDebug"},
|
||||
{kNtImageDirectoryEntryArchitecture, "kNtImageDirectoryEntryArchitecture"},
|
||||
{kNtImageDirectoryEntryGlobalptr, "kNtImageDirectoryEntryGlobalptr"},
|
||||
{kNtImageDirectoryEntryTls, "kNtImageDirectoryEntryTls"},
|
||||
{kNtImageDirectoryEntryLoadConfig, "kNtImageDirectoryEntryLoadConfig"},
|
||||
{kNtImageDirectoryEntryBoundImport, "kNtImageDirectoryEntryBoundImport"},
|
||||
{kNtImageDirectoryEntryIat, "kNtImageDirectoryEntryIat"},
|
||||
{kNtImageDirectoryEntryDelayImport, "kNtImageDirectoryEntryDelayImport"},
|
||||
{kNtImageDirectoryEntryComDescriptor,
|
||||
"kNtImageDirectoryEntryComDescriptor"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kNtImageCharacteristicNames[] = {
|
||||
{kNtImageFileRelocsStripped, "kNtImageFileRelocsStripped"},
|
||||
{kNtImageFileExecutableImage, "kNtImageFileExecutableImage"},
|
||||
{kNtImageFileLineNumsStripped, "kNtImageFileLineNumsStripped"},
|
||||
{kNtImageFileLocalSymsStripped, "kNtImageFileLocalSymsStripped"},
|
||||
{kNtImageFileAggresiveWsTrim, "kNtImageFileAggresiveWsTrim"},
|
||||
{kNtImageFileLargeAddressAware, "kNtImageFileLargeAddressAware"},
|
||||
{kNtImageFileBytesReversedLo, "kNtImageFileBytesReversedLo"},
|
||||
{kNtImageFile32bitMachine, "kNtImageFile32bitMachine"},
|
||||
{kNtImageFileDebugStripped, "kNtImageFileDebugStripped"},
|
||||
{kNtImageFileRemovableRunFromSwap, "kNtImageFileRemovableRunFromSwap"},
|
||||
{kNtImageFileNetRunFromSwap, "kNtImageFileNetRunFromSwap"},
|
||||
{kNtImageFileSystem, "kNtImageFileSystem"},
|
||||
{kNtImageFileDll, "kNtImageFileDll"},
|
||||
{kNtImageFileUpSystemOnly, "kNtImageFileUpSystemOnly"},
|
||||
{kNtImageFileBytesReversedHi, "kNtImageFileBytesReversedHi"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kNtPeSectionNames[] = {
|
||||
{kNtPeSectionCntCode, "kNtPeSectionCntCode"},
|
||||
{kNtPeSectionCntInitializedData, "kNtPeSectionCntInitializedData"},
|
||||
{kNtPeSectionCntUninitializedData, "kNtPeSectionCntUninitializedData"},
|
||||
{kNtPeSectionGprel, "kNtPeSectionGprel"},
|
||||
{kNtPeSectionMemDiscardable, "kNtPeSectionMemDiscardable"},
|
||||
{kNtPeSectionMemNotCached, "kNtPeSectionMemNotCached"},
|
||||
{kNtPeSectionMemNotPaged, "kNtPeSectionMemNotPaged"},
|
||||
{kNtPeSectionMemShared, "kNtPeSectionMemShared"},
|
||||
{kNtPeSectionMemExecute, "kNtPeSectionMemExecute"},
|
||||
{kNtPeSectionMemRead, "kNtPeSectionMemRead"},
|
||||
{kNtPeSectionMemWrite, "kNtPeSectionMemWrite"},
|
||||
{0, 0},
|
||||
};
|
18
tool/decode/lib/peidnames.h
Normal file
18
tool/decode/lib/peidnames.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_PEIDNAMES_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_PEIDNAMES_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const struct IdName kNtImageFileMachineNames[];
|
||||
extern const struct IdName kNtPeOptionalHeaderMagicNames[];
|
||||
extern const struct IdName kNtImageCharacteristicNames[];
|
||||
extern const struct IdName kNtImageDllcharacteristicNames[];
|
||||
extern const struct IdName kNtImageSubsystemNames[];
|
||||
extern const struct IdName kNtImageScnNames[];
|
||||
extern const struct IdName kNtImageDirectoryEntryNames[];
|
||||
extern const struct IdName kNtPeSectionNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_PEIDNAMES_H_ */
|
73
tool/decode/lib/pollnames.S
Normal file
73
tool/decode/lib/pollnames.S
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/relocations.h"
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
.Lrows = 0 # w/ 2 cols
|
||||
|
||||
.macro .tab sym:req str
|
||||
.pushsection .rodata.str1.1,"aSM",@progbits,1
|
||||
.L\@: .asciz "\str"
|
||||
.popsection
|
||||
.long RVA(\sym)
|
||||
.long RVA(.L\@)
|
||||
.Lrows = .Lrows + 1
|
||||
.endm
|
||||
|
||||
.initro 301,_init_kPollNames
|
||||
kPollNamesRo:
|
||||
.tab POLLNVAL "POLLNVAL"
|
||||
.tab POLLWRNORM "POLLWRNORM"
|
||||
.tab POLLWRBAND "POLLWRBAND"
|
||||
.tab POLLRDNORM "POLLRDNORM"
|
||||
.tab POLLRDHUP "POLLRDHUP"
|
||||
.tab POLLRDBAND "POLLRDBAND"
|
||||
.tab POLLHUP "POLLHUP"
|
||||
.tab POLLERR "POLLERR"
|
||||
.tab POLLPRI "POLLPRI"
|
||||
.tab POLLOUT "POLLOUT"
|
||||
.tab POLLIN "POLLIN"
|
||||
.endobj kPollNamesRo,globl,hidden
|
||||
.previous
|
||||
|
||||
/ Mapping of poll() flags to their string names.
|
||||
/ @see recreateflags()
|
||||
.initbss 301,_init_kPollNames
|
||||
kPollNames:
|
||||
.rept .Lrows
|
||||
.quad 0 # unsigned long id
|
||||
.quad 0 # const char *const name
|
||||
.endr
|
||||
.quad 0,0 # terminator row
|
||||
.endobj kPollNames,globl
|
||||
.previous
|
||||
|
||||
.init.start 301,_init_kPollNames
|
||||
pushpop .Lrows,%rcx # relocate RO→BSS b/c -fPIE crap
|
||||
0: lodsl
|
||||
mov (%rbx,%rax),%rax # read what systemfive.S decoded
|
||||
stosq
|
||||
lodsl
|
||||
add %rbx,%rax # %rbx is image base (cosmo abi)
|
||||
stosq
|
||||
loop 0b
|
||||
add $16,%rdi
|
||||
.init.end 301,_init_kPollNames
|
11
tool/decode/lib/pollnames.h
Normal file
11
tool/decode/lib/pollnames.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_POLLNAMES_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_POLLNAMES_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern struct IdName kPollNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_POLLNAMES_H_ */
|
55
tool/decode/lib/socknames.c
Normal file
55
tool/decode/lib/socknames.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ai.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "tool/decode/lib/socknames.h"
|
||||
|
||||
const struct IdName kAddressFamilyNames[] = {
|
||||
{AF_UNSPEC, "AF_UNSPEC"},
|
||||
{AF_UNIX, "AF_UNIX"},
|
||||
{AF_INET, "AF_INET"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kSockTypeNames[] = {
|
||||
{SOCK_STREAM, "SOCK_STREAM"},
|
||||
{SOCK_DGRAM, "SOCK_DGRAM"},
|
||||
{SOCK_RAW, "SOCK_RAW"},
|
||||
{SOCK_RDM, "SOCK_RDM"},
|
||||
{SOCK_SEQPACKET, "SOCK_SEQPACKET"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kAddrInfoFlagNames[] = {
|
||||
{AI_PASSIVE, "AI_PASSIVE"},
|
||||
{AI_CANONNAME, "AI_CANONNAME"},
|
||||
{AI_NUMERICHOST, "AI_NUMERICHOST"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kProtocolNames[] = {
|
||||
{IPPROTO_IP, "IPPROTO_IP"}, {IPPROTO_ICMP, "IPPROTO_ICMP"},
|
||||
{IPPROTO_TCP, "IPPROTO_TCP"}, {IPPROTO_UDP, "IPPROTO_UDP"},
|
||||
{IPPROTO_RAW, "IPPROTO_RAW"}, {0, 0},
|
||||
};
|
14
tool/decode/lib/socknames.h
Normal file
14
tool/decode/lib/socknames.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_SOCKNAMES_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_SOCKNAMES_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const struct IdName kAddressFamilyNames[];
|
||||
extern const struct IdName kSockTypeNames[];
|
||||
extern const struct IdName kAddrInfoFlagNames[];
|
||||
extern const struct IdName kProtocolNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_SOCKNAMES_H_ */
|
60
tool/decode/lib/titlegen.c
Normal file
60
tool/decode/lib/titlegen.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/decode/lib/titlegen.h"
|
||||
|
||||
const struct Modeline kModelineAsm = {
|
||||
" mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 ",
|
||||
" set et ft=asm ts=8 sw=8 fenc=utf-8 "};
|
||||
|
||||
/**
|
||||
* Displays one of those ANSI block source dividers we love so much.
|
||||
*/
|
||||
void showtitle(const char *brand, const char *tool, const char *title,
|
||||
const char *description, const struct Modeline *modeline) {
|
||||
char buf[512], *p;
|
||||
p = stpcpy(buf, brand);
|
||||
if (tool) {
|
||||
p = stpcpy(stpcpy(p, " § "), tool);
|
||||
if (title) {
|
||||
p = stpcpy(stpcpy(p, " » "), title);
|
||||
}
|
||||
}
|
||||
printf("/*");
|
||||
if (modeline) {
|
||||
printf("-*-%-71s-*-│\n│vi:%-72s:vi│\n╞", modeline->emacs, modeline->vim);
|
||||
for (unsigned i = 0; i < 78; ++i) printf("═");
|
||||
printf("╡\n│ %-76s ", buf);
|
||||
} else {
|
||||
for (unsigned i = 0; i < 75; ++i) printf("─");
|
||||
printf("│─╗\n│ %-73s ─╬─", buf);
|
||||
}
|
||||
printf("│\n╚─");
|
||||
for (unsigned i = 0; i < 75; ++i) printf("─");
|
||||
printf("%s", modeline ? "─" : "│");
|
||||
if (description) {
|
||||
/* TODO(jart): paragraph fill */
|
||||
printf("─╝\n%s ", description);
|
||||
} else {
|
||||
}
|
||||
printf("*/\n");
|
||||
}
|
18
tool/decode/lib/titlegen.h
Normal file
18
tool/decode/lib/titlegen.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_TITLEGEN_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_TITLEGEN_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Modeline {
|
||||
const char *emacs;
|
||||
const char *vim;
|
||||
};
|
||||
|
||||
extern const struct Modeline kModelineAsm;
|
||||
|
||||
void showtitle(const char *brand, const char *tool, const char *title,
|
||||
const char *description, const struct Modeline *modeline);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_TITLEGEN_H_ */
|
29
tool/decode/lib/x86gradenames.c
Normal file
29
tool/decode/lib/x86gradenames.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/x86info.h"
|
||||
#include "tool/decode/lib/x86idnames.h"
|
||||
|
||||
const struct IdName kX86GradeNames[] = {
|
||||
{X86_GRADE_UNKNOWN, "Unknown"}, {X86_GRADE_APPLIANCE, "Appliance"},
|
||||
{X86_GRADE_MOBILE, "Mobile"}, {X86_GRADE_TABLET, "Tablet"},
|
||||
{X86_GRADE_DESKTOP, "Desktop"}, {X86_GRADE_CLIENT, "Client"},
|
||||
{X86_GRADE_DENSITY, "Density"}, {X86_GRADE_SERVER, "Server"},
|
||||
{X86_GRADE_SCIENCE, "Science"}, {0, 0},
|
||||
};
|
12
tool/decode/lib/x86idnames.h
Normal file
12
tool/decode/lib/x86idnames.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_X86IDNAMES_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_X86IDNAMES_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const struct IdName kX86MarchNames[];
|
||||
extern const struct IdName kX86GradeNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_X86IDNAMES_H_ */
|
47
tool/decode/lib/x86marchnames.c
Normal file
47
tool/decode/lib/x86marchnames.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/x86info.h"
|
||||
#include "tool/decode/lib/x86idnames.h"
|
||||
|
||||
const struct IdName kX86MarchNames[] = {
|
||||
{X86_MARCH_UNKNOWN, "Unknown"},
|
||||
{X86_MARCH_CORE2, "Core 2"},
|
||||
{X86_MARCH_NEHALEM, "Nehalem"},
|
||||
{X86_MARCH_WESTMERE, "Westmere"},
|
||||
{X86_MARCH_SANDYBRIDGE, "Sandybridge"},
|
||||
{X86_MARCH_IVYBRIDGE, "Ivybridge"},
|
||||
{X86_MARCH_HASWELL, "Haswell"},
|
||||
{X86_MARCH_BROADWELL, "Broadwell"},
|
||||
{X86_MARCH_SKYLAKE, "Skylake"},
|
||||
{X86_MARCH_KABYLAKE, "Kabylake"},
|
||||
{X86_MARCH_CANNONLAKE, "Cannonlake"},
|
||||
{X86_MARCH_ICELAKE, "Icelake"},
|
||||
{X86_MARCH_TIGERLAKE, "Tigerlake"},
|
||||
{X86_MARCH_BONNELL, "Bonnell"},
|
||||
{X86_MARCH_SALTWELL, "Saltwell"},
|
||||
{X86_MARCH_SILVERMONT, "Silvermont"},
|
||||
{X86_MARCH_AIRMONT, "Airmont"},
|
||||
{X86_MARCH_GOLDMONT, "Goldmont"},
|
||||
{X86_MARCH_GOLDMONTPLUS, "Goldmont Plus"},
|
||||
{X86_MARCH_TREMONT, "Tremont"},
|
||||
{X86_MARCH_KNIGHTSLANDING, "Knights Landing"},
|
||||
{X86_MARCH_KNIGHTSMILL, "Knights Mill"},
|
||||
{0, 0},
|
||||
};
|
47
tool/decode/lib/xederrors.c
Normal file
47
tool/decode/lib/xederrors.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/decode/lib/idname.h"
|
||||
|
||||
const struct IdName kXedErrorNames[] = {
|
||||
{XED_ERROR_NONE, "NONE"},
|
||||
{XED_ERROR_BUFFER_TOO_SHORT, "BUFFER_TOO_SHORT"},
|
||||
{XED_ERROR_GENERAL_ERROR, "GENERAL_ERROR"},
|
||||
{XED_ERROR_INVALID_FOR_CHIP, "INVALID_FOR_CHIP"},
|
||||
{XED_ERROR_BAD_REGISTER, "BAD_REGISTER"},
|
||||
{XED_ERROR_BAD_LOCK_PREFIX, "BAD_LOCK_PREFIX"},
|
||||
{XED_ERROR_BAD_REP_PREFIX, "BAD_REP_PREFIX"},
|
||||
{XED_ERROR_BAD_LEGACY_PREFIX, "BAD_LEGACY_PREFIX"},
|
||||
{XED_ERROR_BAD_REX_PREFIX, "BAD_REX_PREFIX"},
|
||||
{XED_ERROR_BAD_EVEX_UBIT, "BAD_EVEX_UBIT"},
|
||||
{XED_ERROR_BAD_MAP, "BAD_MAP"},
|
||||
{XED_ERROR_BAD_EVEX_V_PRIME, "BAD_EVEX_V_PRIME"},
|
||||
{XED_ERROR_BAD_EVEX_Z_NO_MASKING, "BAD_EVEX_Z_NO_MASKING"},
|
||||
{XED_ERROR_NO_OUTPUT_POINTER, "NO_OUTPUT_POINTER"},
|
||||
{XED_ERROR_NO_AGEN_CALL_BACK_REGISTERED, "NO_AGEN_CALL_BACK_REGISTERED"},
|
||||
{XED_ERROR_BAD_MEMOP_INDEX, "BAD_MEMOP_INDEX"},
|
||||
{XED_ERROR_CALLBACK_PROBLEM, "CALLBACK_PROBLEM"},
|
||||
{XED_ERROR_GATHER_REGS, "GATHER_REGS"},
|
||||
{XED_ERROR_INSTR_TOO_LONG, "INSTR_TOO_LONG"},
|
||||
{XED_ERROR_INVALID_MODE, "INVALID_MODE"},
|
||||
{XED_ERROR_BAD_EVEX_LL, "BAD_EVEX_LL"},
|
||||
{XED_ERROR_UNIMPLEMENTED, "UNIMPLEMENTED"},
|
||||
{0, 0},
|
||||
};
|
11
tool/decode/lib/xederrors.h
Normal file
11
tool/decode/lib/xederrors.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_XEDERRORS_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_XEDERRORS_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const struct IdName kXedErrorNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_XEDERRORS_H_ */
|
71
tool/decode/lib/zipnames.c
Normal file
71
tool/decode/lib/zipnames.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/zip.h"
|
||||
#include "tool/decode/lib/zipnames.h"
|
||||
|
||||
const struct IdName kZipCompressionNames[] = {
|
||||
{kZipCompressionNone, "kZipCompressionNone"},
|
||||
{kZipCompressionDeflate, "kZipCompressionDeflate"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kZipExtraNames[] = {
|
||||
{kZipExtraZip64, "kZipExtraZip64"},
|
||||
{kZipExtraNtfs, "kZipExtraNtfs"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kZipIattrNames[] = {
|
||||
{kZipIattrBinary, "kZipIattrBinary"},
|
||||
{kZipIattrAscii, "kZipIattrAscii"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kZipOsNames[] = {
|
||||
{kZipOsDos, "kZipOsDos"},
|
||||
{kZipOsAmiga, "kZipOsAmiga"},
|
||||
{kZipOsOpenvms, "kZipOsOpenvms"},
|
||||
{kZipOsUnix, "kZipOsUnix"},
|
||||
{kZipOsVmcms, "kZipOsVmcms"},
|
||||
{kZipOsAtarist, "kZipOsAtarist"},
|
||||
{kZipOsOs2hpfs, "kZipOsOs2hpfs"},
|
||||
{kZipOsMacintosh, "kZipOsMacintosh"},
|
||||
{kZipOsZsystem, "kZipOsZsystem"},
|
||||
{kZipOsCpm, "kZipOsCpm"},
|
||||
{kZipOsWindowsntfs, "kZipOsWindowsntfs"},
|
||||
{kZipOsMvsos390zos, "kZipOsMvsos390zos"},
|
||||
{kZipOsVse, "kZipOsVse"},
|
||||
{kZipOsAcornrisc, "kZipOsAcornrisc"},
|
||||
{kZipOsVfat, "kZipOsVfat"},
|
||||
{kZipOsAltmvs, "kZipOsAltmvs"},
|
||||
{kZipOsBeos, "kZipOsBeos"},
|
||||
{kZipOsTandem, "kZipOsTandem"},
|
||||
{kZipOsOs400, "kZipOsOs400"},
|
||||
{kZipOsOsxdarwin, "kZipOsOsxdarwin"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
const struct IdName kZipEraNames[] = {
|
||||
{kZipEra1989, "kZipEra1989"},
|
||||
{kZipEra1993, "kZipEra1993"},
|
||||
{kZipEra2001, "kZipEra2001"},
|
||||
{0, 0},
|
||||
};
|
15
tool/decode/lib/zipnames.h
Normal file
15
tool/decode/lib/zipnames.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_DECODE_LIB_ZIPNAMES_H_
|
||||
#define COSMOPOLITAN_TOOL_DECODE_LIB_ZIPNAMES_H_
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const struct IdName kZipCompressionNames[];
|
||||
extern const struct IdName kZipExtraNames[];
|
||||
extern const struct IdName kZipIattrNames[];
|
||||
extern const struct IdName kZipOsNames[];
|
||||
extern const struct IdName kZipEraNames[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_DECODE_LIB_ZIPNAMES_H_ */
|
263
tool/decode/macho.c
Normal file
263
tool/decode/macho.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/macho.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "tool/decode/lib/asmcodegen.h"
|
||||
#include "tool/decode/lib/flagger.h"
|
||||
#include "tool/decode/lib/machoidnames.h"
|
||||
#include "tool/decode/lib/titlegen.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Apple Mach-O metadata disassembler.
|
||||
*/
|
||||
|
||||
static const char *path;
|
||||
static struct MachoHeader *macho;
|
||||
static size_t machosize;
|
||||
|
||||
static void startfile(void) {
|
||||
showtitle("αcτµαlly pδrταblε εxεcµταblε", "tool/decode/macho", NULL, NULL,
|
||||
&kModelineAsm);
|
||||
printf("#include \"libc/macho.h\"\n\n", path);
|
||||
}
|
||||
|
||||
static void showmachoheader(void) {
|
||||
#if !defined(TRUSTWORTHY) && !defined(MACHO_TRUSTWORTHY)
|
||||
if (sizeof(struct MachoHeader) > machosize) {
|
||||
fprintf(stderr, "error: %'s: MachoHeader overruns eof\n", path);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
showtitle(basename(path), "macho", "header", NULL, NULL);
|
||||
printf("\n");
|
||||
showinthex(macho->magic);
|
||||
showinthex(macho->arch);
|
||||
showinthex(macho->arch2);
|
||||
show(".long",
|
||||
firstnonnull(findnamebyid(kMachoFileTypeNames, macho->filetype),
|
||||
format(b1, "%#x", macho->filetype)),
|
||||
"macho->filetype");
|
||||
showinthex(macho->loadcount);
|
||||
showinthex(macho->loadsize);
|
||||
show(".long",
|
||||
firstnonnull(recreateflags(kMachoFlagNames, macho->flags),
|
||||
format(b1, "%#x", macho->flags)),
|
||||
"macho->flags");
|
||||
showinthex(macho->__reserved);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void showmachosection(struct MachoSection *section) {
|
||||
show(".ascin", format(b1, "%`'s,16", section->name), "section->name");
|
||||
show(".ascin", format(b1, "%`'s,16", section->commandname),
|
||||
"section->commandname");
|
||||
showint64hex(section->vaddr);
|
||||
showint64hex(section->memsz);
|
||||
showinthex(section->offset);
|
||||
showinthex(section->alignlog2);
|
||||
showinthex(section->relotaboff);
|
||||
showinthex(section->relocount);
|
||||
showinthex(section->attr);
|
||||
show(".long",
|
||||
format(b1, "%d,%d,%d", section->__reserved[0], section->__reserved[1],
|
||||
section->__reserved[2]),
|
||||
"section->__reserved");
|
||||
}
|
||||
|
||||
static void showmacholoadsegment(unsigned i, struct MachoLoadSegment *loadseg) {
|
||||
assert(loadseg->size ==
|
||||
sizeof(struct MachoLoadSegment) +
|
||||
loadseg->sectioncount * sizeof(struct MachoSection));
|
||||
#if !defined(TRUSTWORTHY) && !defined(MACHO_TRUSTWORTHY)
|
||||
if ((intptr_t)loadseg + sizeof(struct MachoLoadSegment) +
|
||||
loadseg->sectioncount * sizeof(struct MachoSection) >
|
||||
(intptr_t)macho + machosize) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
show(".ascin", format(b1, "%`'s,16", loadseg->name), "loadseg->name");
|
||||
showint64hex(loadseg->vaddr);
|
||||
showint64hex(loadseg->memsz);
|
||||
showint64hex(loadseg->offset);
|
||||
showint64hex(loadseg->filesz);
|
||||
show(".long",
|
||||
firstnonnull(recreateflags(kMachoVmProtNames, loadseg->maxprot),
|
||||
format(b1, "%#x", loadseg->maxprot)),
|
||||
"loadseg->maxprot");
|
||||
show(".long",
|
||||
firstnonnull(recreateflags(kMachoVmProtNames, loadseg->initprot),
|
||||
format(b1, "%#x", loadseg->initprot)),
|
||||
"loadseg->initprot");
|
||||
showinthex(loadseg->sectioncount);
|
||||
show(".long",
|
||||
firstnonnull(recreateflags(kMachoSegmentFlagNames, loadseg->flags),
|
||||
format(b1, "%#x", loadseg->flags)),
|
||||
"loadseg->flags");
|
||||
for (unsigned j = 0; j < loadseg->sectioncount; ++j) {
|
||||
printf("%d:", (i + 1) * 100 + (j + 1) * 10);
|
||||
showmachosection((struct MachoSection *)((intptr_t)loadseg +
|
||||
sizeof(struct MachoLoadSegment) +
|
||||
j * sizeof(struct MachoSection)));
|
||||
}
|
||||
}
|
||||
|
||||
static void showmacholoadsymtabshowall(struct MachoLoadSymtab *ls) {
|
||||
assert(ls->size == sizeof(struct MachoLoadSymtab));
|
||||
#if !defined(TRUSTWORTHY) && !defined(MACHO_TRUSTWORTHY)
|
||||
if ((intptr_t)ls + sizeof(struct MachoLoadSymtab) >
|
||||
(intptr_t)macho + machosize) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
showinthex(ls->offset);
|
||||
showinthex(ls->count);
|
||||
showinthex(ls->stroff);
|
||||
showinthex(ls->strsize);
|
||||
}
|
||||
|
||||
static void showmacholoaduuid(struct MachoLoadUuid *lu) {
|
||||
assert(lu->size == sizeof(struct MachoLoadUuid));
|
||||
#if !defined(TRUSTWORTHY) && !defined(MACHO_TRUSTWORTHY)
|
||||
if ((intptr_t)lu + sizeof(struct MachoLoadUuid) >
|
||||
(intptr_t)macho + machosize) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
printf("\t.byte\t");
|
||||
for (unsigned i = 0; i < 16; ++i) {
|
||||
if (i) {
|
||||
if (i == 8) {
|
||||
printf("\n\t.byte\t");
|
||||
} else {
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
printf("%#hhx", lu->uuid[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void showmacholoadsourceversion(
|
||||
struct MachoLoadSourceVersionCommand *sv) {
|
||||
assert(sv->size == sizeof(struct MachoLoadSourceVersionCommand));
|
||||
#if !defined(TRUSTWORTHY) && !defined(MACHO_TRUSTWORTHY)
|
||||
if ((intptr_t)sv + sizeof(struct MachoLoadSourceVersionCommand) >
|
||||
(intptr_t)macho + machosize) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
showint64hex(sv->version);
|
||||
}
|
||||
|
||||
static void showmacholoadunixthread(struct MachoLoadThreadCommand *lc) {
|
||||
assert(lc->size == 4 + 4 + 4 + 4 + lc->count * 4);
|
||||
showinthex(lc->flavor);
|
||||
showint(lc->count);
|
||||
for (unsigned i = 0; i < lc->count; ++i) {
|
||||
showinthex(lc->wut[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void showmacholoadcommand(struct MachoLoadCommand *lc, unsigned i) {
|
||||
#if !defined(TRUSTWORTHY) && !defined(MACHO_TRUSTWORTHY)
|
||||
if ((intptr_t)lc > (intptr_t)macho + machosize ||
|
||||
(intptr_t)lc + lc->size > (intptr_t)macho + machosize) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
showorg((intptr_t)lc - (intptr_t)macho);
|
||||
printf("%d:", (i + 1) * 10);
|
||||
show(".long",
|
||||
firstnonnull(findnamebyid(kMachoLoadCommandNames, lc->command),
|
||||
format(b1, "%#x", lc->command)),
|
||||
"lc->command");
|
||||
showinthex(lc->size);
|
||||
switch (lc->command) {
|
||||
case MAC_LC_SEGMENT_64:
|
||||
showmacholoadsegment(i, (struct MachoLoadSegment *)lc);
|
||||
break;
|
||||
case MAC_LC_SYMTAB:
|
||||
showmacholoadsymtabshowall((struct MachoLoadSymtab *)lc);
|
||||
break;
|
||||
case MAC_LC_UUID:
|
||||
showmacholoaduuid((struct MachoLoadUuid *)lc);
|
||||
break;
|
||||
case MAC_LC_SOURCE_VERSION:
|
||||
showmacholoadsourceversion((struct MachoLoadSourceVersionCommand *)lc);
|
||||
break;
|
||||
case MAC_LC_UNIXTHREAD:
|
||||
showmacholoadunixthread((struct MachoLoadThreadCommand *)lc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void showmacholoadcommands(void) {
|
||||
#if !defined(TRUSTWORTHY) && !defined(MACHO_TRUSTWORTHY)
|
||||
if (sizeof(struct MachoHeader) + macho->loadsize > machosize) {
|
||||
fprintf(stderr, "error: %'s: macho->loadsize overruns eof\n", path);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
unsigned i = 0;
|
||||
const unsigned count = macho->loadcount;
|
||||
for (struct MachoLoadCommand *lc =
|
||||
(void *)((intptr_t)macho + sizeof(struct MachoHeader));
|
||||
i < count; ++i, lc = (void *)((intptr_t)lc + lc->size)) {
|
||||
showmacholoadcommand(lc, i);
|
||||
}
|
||||
}
|
||||
|
||||
void showall(void) {
|
||||
startfile();
|
||||
showmachoheader();
|
||||
showmacholoadcommands();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int64_t fd;
|
||||
struct stat st[1];
|
||||
if (argc != 2) fprintf(stderr, "usage: %s FILE\n", argv[0]), exit(1);
|
||||
if ((fd = open((path = argv[1]), O_RDONLY)) == -1 || fstat(fd, st) == -1 ||
|
||||
(macho = mmap(NULL, (machosize = st->st_size), PROT_READ, MAP_SHARED, fd,
|
||||
0)) == MAP_FAILED) {
|
||||
fprintf(stderr, "error: %'s %m\n", path);
|
||||
exit(1);
|
||||
}
|
||||
if (macho->magic != 0xFEEDFACF) {
|
||||
fprintf(stderr, "error: %'s not a macho x64 executable\n", path);
|
||||
exit(1);
|
||||
}
|
||||
showall();
|
||||
munmap(macho, machosize);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
121
tool/decode/mkcombos.c
Normal file
121
tool/decode/mkcombos.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/decode/lib/bitabuilder.h"
|
||||
|
||||
static size_t linecap;
|
||||
static FILE *fin, *fout;
|
||||
static uint32_t bit, maxbit;
|
||||
static struct BitaBuilder *bitset;
|
||||
static char *line, *tok, *s1, *category, *g_inpath, *g_outpath;
|
||||
|
||||
noreturn void ShowUsage(FILE *f, int rc) {
|
||||
fprintf(f, "Usage: %s [-o OUTPUT] [INPUT]\n", "Usage",
|
||||
program_invocation_name);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
g_inpath = "/dev/stdin";
|
||||
g_outpath = "/dev/stdout";
|
||||
while ((opt = getopt(argc, argv, "?ho:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
g_outpath = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
ShowUsage(stdout, EXIT_SUCCESS);
|
||||
default:
|
||||
ShowUsage(stderr, EX_USAGE);
|
||||
}
|
||||
}
|
||||
if (argc - optind) {
|
||||
g_inpath = argv[optind];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds sparse unicode dataset for combining codepoints, e.g.
|
||||
*
|
||||
* UNDERLINING
|
||||
*
|
||||
* - COMBINING MACRON BELOW U+0331 (\xCC\xB1)
|
||||
* e.g. A̱ḆC̱Ḏ (too short) 41CCB1 42CCB1 43CCB1 44CCB1
|
||||
*
|
||||
* - COMBINING DOUBLE MACRON BELOW U+035F (\xCD\x9F)
|
||||
* e.g. A͟B͟C͟D͟ (too long) 41CD9F 42CD9F 43CD9F 44CD9F
|
||||
*
|
||||
* - DOUBLE PLUS COMBINING MACRON BELOW 3×U+035F + 1×U+0331
|
||||
* e.g. A͟B͟C͟Ḏ (just right) 41CCB1 42CCB1 43CCB1 44CD9F
|
||||
*
|
||||
* STRIKETHROUGH
|
||||
*
|
||||
* - COMBINING LONG STROKE OVERLAY U+0336 (\xCC\xB6)
|
||||
* e.g. A̶B̶C̶D̶ 41CCB6 42CCB6 43CCB6 44CCB6
|
||||
*
|
||||
* - COMBINING SHORT STROKE OVERLAY U+0335 (\xCC\xB5)
|
||||
* e.g. A̵B̵C̵D̵ 41CCB5 42CCB5 43CCB5 44CCB5
|
||||
*
|
||||
* - COMBINING SHORT SOLIDUS OVERLAY U+0337 (\xCC\xB7)
|
||||
* e.g. A̷B̷C̷D̷ 41CCB7 42CCB7 43CCB7 44CCB7
|
||||
*
|
||||
* - COMBINING LONG SOLIDUS OVERLAY U+0338 (\xCC\xB8)
|
||||
* e.g. A̸B̸C̸D̸ 41CCB8 42CCB8 43CCB8 44CCB8
|
||||
*
|
||||
* @see unicode.org/reports/tr11/#Definitions
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
GetOpts(argc, argv);
|
||||
CHECK_NOTNULL(fin = fopen(g_inpath, "r"));
|
||||
bitset = bitabuilder_new();
|
||||
while ((getline(&line, &linecap, fin)) != -1) {
|
||||
tok = line;
|
||||
s1 = strsep(&tok, ";");
|
||||
strsep(&tok, ";");
|
||||
category = strsep(&tok, ";");
|
||||
if (!s1 || !category) continue;
|
||||
bit = strtoimax(s1, NULL, 16);
|
||||
if (bit != 0x00AD &&
|
||||
((0x1160 <= bit && bit <= 0x11FF) ||
|
||||
(strcmp(category, "Me") == 0 || strcmp(category, "Mn") == 0 ||
|
||||
strcmp(category, "Cf") == 0 || strcmp(category, "Sk") == 0))) {
|
||||
maxbit = max(bit, maxbit);
|
||||
CHECK(bitabuilder_setbit(bitset, bit));
|
||||
}
|
||||
}
|
||||
CHECK_NOTNULL(fout = fopen(g_outpath, "wb"));
|
||||
CHECK(bitabuilder_fwrite(bitset, fout));
|
||||
bitabuilder_free(&bitset);
|
||||
return fclose(fin) | fclose(fout);
|
||||
}
|
104
tool/decode/mkwides.c
Normal file
104
tool/decode/mkwides.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "tool/decode/lib/bitabuilder.h"
|
||||
|
||||
static FILE *fin, *fout;
|
||||
static char width, *line;
|
||||
static size_t linecap, i, x, y;
|
||||
static struct BitaBuilder *bitset;
|
||||
static char *g_inpath, *g_outpath;
|
||||
|
||||
noreturn void ShowUsage(FILE *f, int rc) {
|
||||
fprintf(f, "Usage: %s [-o OUTPUT] [INPUT]\n", "Usage",
|
||||
program_invocation_name);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
g_inpath = "/dev/stdin";
|
||||
g_outpath = "/dev/stdout";
|
||||
while ((opt = getopt(argc, argv, "?ho:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
g_outpath = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
ShowUsage(stdout, EXIT_SUCCESS);
|
||||
default:
|
||||
ShowUsage(stderr, EX_USAGE);
|
||||
}
|
||||
}
|
||||
if (argc - optind) {
|
||||
g_inpath = argv[optind];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts official UNICODE ‘monospace widths’ (yup) to a bitset.
|
||||
*
|
||||
* (╯°□°)╯︵ ̲┻̲━̲┻
|
||||
* 要依法治国是赞美那些谁是公义的和惩罚恶人。 - 韩非
|
||||
*
|
||||
* 172kB TXT → 32kB bits → 525 bytes lz4
|
||||
*
|
||||
* @note this tool may print binary to stdout
|
||||
* @see libc/kompressor/lz4decode.c
|
||||
* @see tool/viz/bing.c
|
||||
* @see tool/viz/fold.c
|
||||
* @see unicode.org/reports/tr11/#Definitions
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
GetOpts(argc, argv);
|
||||
bitset = bitabuilder_new();
|
||||
CHECK_NOTNULL(fin = fopen(g_inpath, "r"));
|
||||
while ((getline(&line, &linecap, fin)) != -1) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
if (sscanf(line, "%x..%x;%c", &x, &y, &width) != 3) {
|
||||
if (sscanf(line, "%x;%c", &x, &width) == 2) {
|
||||
y = x;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CHECK_LE(x, y);
|
||||
if (width == 'F' /* full-width */ || width == 'W' /* wide */) {
|
||||
for (i = x; i <= y; ++i) {
|
||||
CHECK(bitabuilder_setbit(bitset, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK_NOTNULL(fout = fopen(g_outpath, "wb"));
|
||||
CHECK(bitabuilder_fwrite(bitset, fout));
|
||||
bitabuilder_free(&bitset);
|
||||
return fclose(fin) | fclose(fout);
|
||||
}
|
228
tool/decode/pe2.c
Normal file
228
tool/decode/pe2.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/nt/struct/imagentheaders.h"
|
||||
#include "libc/nt/struct/imageoptionalheader.h"
|
||||
#include "libc/pe.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/decode/lib/asmcodegen.h"
|
||||
#include "tool/decode/lib/flagger.h"
|
||||
#include "tool/decode/lib/peidnames.h"
|
||||
#include "tool/decode/lib/titlegen.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Portable executable metadata disassembler.
|
||||
* @see https://www.aldeid.com/wiki/PE-Portable-executable
|
||||
*/
|
||||
|
||||
static const char *path;
|
||||
static struct NtImageDosHeader *mz;
|
||||
static size_t mzsize;
|
||||
|
||||
static struct XedDecodedInst *ildreal(void *addr) {
|
||||
static struct XedDecodedInst xedd;
|
||||
if (xed_instruction_length_decode(
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_REAL), addr,
|
||||
XED_MAX_INSTRUCTION_BYTES) != XED_ERROR_NONE ||
|
||||
!xedd.decoded_length) {
|
||||
xedd.decoded_length = 1;
|
||||
}
|
||||
return &xedd;
|
||||
}
|
||||
|
||||
static void startfile(void) {
|
||||
showtitle("αcτµαlly pδrταblε εxεcµταblε", "tool/decode/pe", NULL, NULL,
|
||||
&kModelineAsm);
|
||||
printf("#include \"libc/pe.h\"\n\n", path);
|
||||
}
|
||||
|
||||
static void showmzheader(void) {
|
||||
showtitle(basename(path), "dos", "mz header",
|
||||
"\tMZ = Mark 'Zibo' Joseph Zbikowski\n"
|
||||
"\te_cblp: bytes on last page\n"
|
||||
"\te_cp: 512-byte pages in file\n"
|
||||
"\te_crlc: reloc table entry count\n"
|
||||
"\te_cparhdr: data segment file offset / 16\n"
|
||||
"\te_{min,max}alloc: lowers upper bound load / 16\n"
|
||||
"\te_ss: lower bound on stack segment\n"
|
||||
"\te_sp: initialize stack pointer\n"
|
||||
"\te_csum: ∑bₙ checksum don't bother\n"
|
||||
"\te_ip: initial ip value\n"
|
||||
"\te_cs: increases cs load lower bound\n"
|
||||
"\te_lfarlc: reloc table offset\n"
|
||||
"\te_ovno: overlay number\n"
|
||||
"\te_lfanew: portable executable header rva",
|
||||
NULL);
|
||||
printf("\n");
|
||||
show(".ascii", format(b1, "%`'.*s", 2, (const char *)&mz->e_magic),
|
||||
"mz->e_magic");
|
||||
showshorthex(mz->e_cblp);
|
||||
showshorthex(mz->e_cp);
|
||||
showshorthex(mz->e_crlc);
|
||||
showshorthex(mz->e_cparhdr);
|
||||
showshorthex(mz->e_minalloc);
|
||||
showshorthex(mz->e_maxalloc);
|
||||
showshorthex(mz->e_ss);
|
||||
showshorthex(mz->e_sp);
|
||||
showshorthex(mz->e_csum);
|
||||
showshorthex(mz->e_ip);
|
||||
showshorthex(mz->e_cs);
|
||||
showshorthex(mz->e_lfarlc);
|
||||
showshorthex(mz->e_ovno);
|
||||
show(".short",
|
||||
format(b1, "%hn,%hn,%hn,%hn", mz->e_res[0], mz->e_res[1], mz->e_res[2],
|
||||
mz->e_res[3]),
|
||||
"mz->e_res");
|
||||
showshorthex(mz->e_oemid);
|
||||
showshorthex(mz->e_oeminfo);
|
||||
show(".short",
|
||||
format(b1, "%hn,%hn,%hn,%hn,%hn,%hn,%hn,%hn,%hn,%hn", mz->e_res2[0],
|
||||
mz->e_res2[1], mz->e_res2[2], mz->e_res2[3], mz->e_res2[4],
|
||||
mz->e_res2[5], mz->e_res2[6], mz->e_res2[7], mz->e_res2[8],
|
||||
mz->e_res2[9]),
|
||||
"mz->e_res2");
|
||||
showinthex(mz->e_lfanew);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void showdosstub(void) {
|
||||
unsigned char *p = (unsigned char *)mz + sizeof(struct NtImageDosHeader);
|
||||
unsigned char *pe = (mz->e_lfanew ? p + mz->e_lfanew : p + mzsize);
|
||||
pe = min(pe, p + mzsize - XED_MAX_INSTRUCTION_BYTES);
|
||||
while (p < pe) {
|
||||
struct XedDecodedInst *inst = ildreal(p);
|
||||
if (p + inst->decoded_length > pe) break;
|
||||
printf("\t.byte\t");
|
||||
for (unsigned i = 0; i < inst->decoded_length; ++i) {
|
||||
if (i) printf(",");
|
||||
printf("%#hhx", xed_decoded_inst_get_byte(inst, i));
|
||||
}
|
||||
printf("\n");
|
||||
p += inst->decoded_length;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void showpeoptionalheader(struct NtImageOptionalHeader *opt) {
|
||||
showtitle(basename(path), "windows", "pe \"optional\" header", NULL, NULL);
|
||||
printf("\n");
|
||||
show(".short",
|
||||
firstnonnull(findnamebyid(kNtPeOptionalHeaderMagicNames, opt->Magic),
|
||||
format(b1, "%#hx", opt->Magic)),
|
||||
"opt->Magic");
|
||||
showint(opt->MajorLinkerVersion);
|
||||
showint(opt->MinorLinkerVersion);
|
||||
showinthex(opt->SizeOfCode);
|
||||
showinthex(opt->SizeOfInitializedData);
|
||||
showinthex(opt->SizeOfUninitializedData);
|
||||
showinthex(opt->AddressOfEntryPoint);
|
||||
showinthex(opt->BaseOfCode);
|
||||
showint64hex(opt->ImageBase);
|
||||
showinthex(opt->SectionAlignment);
|
||||
showinthex(opt->FileAlignment);
|
||||
showshort(opt->MajorOperatingSystemVersion);
|
||||
showshort(opt->MinorOperatingSystemVersion);
|
||||
showshort(opt->MajorImageVersion);
|
||||
showshort(opt->MinorImageVersion);
|
||||
showshort(opt->MajorSubsystemVersion);
|
||||
showshort(opt->MinorSubsystemVersion);
|
||||
showint(opt->Win32VersionValue);
|
||||
showinthex(opt->SizeOfImage);
|
||||
showinthex(opt->SizeOfHeaders);
|
||||
showinthex(opt->CheckSum);
|
||||
show(".short",
|
||||
firstnonnull(findnamebyid(kNtImageSubsystemNames, opt->Subsystem),
|
||||
format(b1, "%#hx", opt->Subsystem)),
|
||||
"opt->Subsystem");
|
||||
show(".short",
|
||||
firstnonnull(recreateflags(kNtImageDllcharacteristicNames,
|
||||
opt->DllCharacteristics),
|
||||
format(b1, "%#hx", opt->DllCharacteristics)),
|
||||
"opt->DllCharacteristics");
|
||||
showint64hex(opt->SizeOfStackReserve);
|
||||
showint64hex(opt->SizeOfStackCommit);
|
||||
showint64hex(opt->SizeOfHeapReserve);
|
||||
showint64hex(opt->SizeOfHeapCommit);
|
||||
showinthex(opt->LoaderFlags);
|
||||
showinthex(opt->NumberOfRvaAndSizes);
|
||||
}
|
||||
|
||||
static void showpeheader(struct NtImageNtHeaders *pe) {
|
||||
showtitle(basename(path), "windows", "pe header", NULL, NULL);
|
||||
printf("\n");
|
||||
showorg(mz->e_lfanew);
|
||||
show(".ascii", format(b1, "%`'.*s", 4, (const char *)&pe->Signature),
|
||||
"pe->Signature");
|
||||
show(".short",
|
||||
firstnonnull(
|
||||
findnamebyid(kNtImageFileMachineNames, pe->FileHeader.Machine),
|
||||
format(b1, "%#hx", pe->FileHeader.Machine)),
|
||||
"pe->FileHeader.Machine");
|
||||
showshort(pe->FileHeader.NumberOfSections);
|
||||
showinthex(pe->FileHeader.TimeDateStamp);
|
||||
showinthex(pe->FileHeader.PointerToSymbolTable);
|
||||
showint(pe->FileHeader.NumberOfSymbols);
|
||||
showshort(pe->FileHeader.SizeOfOptionalHeader);
|
||||
show(".short",
|
||||
firstnonnull(recreateflags(kNtImageCharacteristicNames,
|
||||
pe->FileHeader.Characteristics),
|
||||
format(b1, "%#hx", pe->FileHeader.Characteristics)),
|
||||
"pe->FileHeader.Characteristics");
|
||||
printf("\n");
|
||||
showpeoptionalheader(pecheckaddress(mz, mzsize, &pe->OptionalHeader,
|
||||
pe->FileHeader.SizeOfOptionalHeader));
|
||||
}
|
||||
|
||||
static void showall(void) {
|
||||
startfile();
|
||||
showmzheader();
|
||||
showdosstub();
|
||||
if (mz->e_lfanew) {
|
||||
showpeheader(pecomputerva(mz, mzsize, mz->e_lfanew,
|
||||
sizeof(struct NtImageFileHeader)));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int64_t fd;
|
||||
struct stat st[1];
|
||||
if (argc != 2) fprintf(stderr, "usage: %s FILE\n", argv[0]), exit(1);
|
||||
if ((fd = open((path = argv[1]), O_RDONLY)) == -1 || fstat(fd, st) == -1 ||
|
||||
(mz = mmap(NULL, (mzsize = st->st_size), PROT_READ, MAP_SHARED, fd, 0)) ==
|
||||
MAP_FAILED) {
|
||||
fprintf(stderr, "error: %'s %m\n", path);
|
||||
exit(1);
|
||||
}
|
||||
if (mz->e_magic != kNtImageDosSignature) {
|
||||
fprintf(stderr, "error: %'s not a dos executable\n", path);
|
||||
exit(1);
|
||||
}
|
||||
showall();
|
||||
munmap(mz, mzsize);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
101
tool/decode/peboff.c
Normal file
101
tool/decode/peboff.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include "libc/nt/struct/peb.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main() {
|
||||
printf("InheritedAddressSpace = 0x%x\n",
|
||||
offsetof(struct NtPeb, InheritedAddressSpace));
|
||||
printf("ReadImageFileExecOptions = 0x%x\n",
|
||||
offsetof(struct NtPeb, ReadImageFileExecOptions));
|
||||
printf("BeingDebugged = 0x%x\n", offsetof(struct NtPeb, BeingDebugged));
|
||||
printf("Mutant = 0x%x\n", offsetof(struct NtPeb, Mutant));
|
||||
printf("ImageBaseAddress = 0x%x\n", offsetof(struct NtPeb, ImageBaseAddress));
|
||||
printf("Ldr = 0x%x\n", offsetof(struct NtPeb, Ldr));
|
||||
printf("ProcessParameters = 0x%x\n",
|
||||
offsetof(struct NtPeb, ProcessParameters));
|
||||
printf("SubSystemData = 0x%x\n", offsetof(struct NtPeb, SubSystemData));
|
||||
printf("ProcessHeap = 0x%x\n", offsetof(struct NtPeb, ProcessHeap));
|
||||
printf("FastPebLock = 0x%x\n", offsetof(struct NtPeb, FastPebLock));
|
||||
printf("KernelCallbackTable = 0x%x\n",
|
||||
offsetof(struct NtPeb, KernelCallbackTable));
|
||||
printf("UserSharedInfoPtr = 0x%x\n",
|
||||
offsetof(struct NtPeb, UserSharedInfoPtr));
|
||||
printf("SystemReserved = 0x%x\n", offsetof(struct NtPeb, SystemReserved));
|
||||
printf("__wut6 = 0x%x\n", offsetof(struct NtPeb, __wut6));
|
||||
printf("__wut7 = 0x%x\n", offsetof(struct NtPeb, __wut7));
|
||||
printf("TlsExpansionCounter = 0x%x\n",
|
||||
offsetof(struct NtPeb, TlsExpansionCounter));
|
||||
printf("TlsBitmap = 0x%x\n", offsetof(struct NtPeb, TlsBitmap));
|
||||
printf("TlsBitmapBits = 0x%x\n", offsetof(struct NtPeb, TlsBitmapBits));
|
||||
printf("ReadOnlySharedMemoryBase = 0x%x\n",
|
||||
offsetof(struct NtPeb, ReadOnlySharedMemoryBase));
|
||||
printf("ReadOnlyStaticServerData = 0x%x\n",
|
||||
offsetof(struct NtPeb, ReadOnlyStaticServerData));
|
||||
printf("AnsiCodePageData = 0x%x\n", offsetof(struct NtPeb, AnsiCodePageData));
|
||||
printf("OemCodePageData = 0x%x\n", offsetof(struct NtPeb, OemCodePageData));
|
||||
printf("UnicodeCaseTableData = 0x%x\n",
|
||||
offsetof(struct NtPeb, UnicodeCaseTableData));
|
||||
printf("NumberOfProcessors = 0x%x\n",
|
||||
offsetof(struct NtPeb, NumberOfProcessors));
|
||||
printf("NtGlobalFlag = 0x%x\n", offsetof(struct NtPeb, NtGlobalFlag));
|
||||
printf("CriticalSectionTimeout = 0x%x\n",
|
||||
offsetof(struct NtPeb, CriticalSectionTimeout));
|
||||
printf("HeapSegmentReserve = 0x%x\n",
|
||||
offsetof(struct NtPeb, HeapSegmentReserve));
|
||||
printf("HeapSegmentCommit = 0x%x\n",
|
||||
offsetof(struct NtPeb, HeapSegmentCommit));
|
||||
printf("HeapDeCommitTotalFreeThreshold = 0x%x\n",
|
||||
offsetof(struct NtPeb, HeapDeCommitTotalFreeThreshold));
|
||||
printf("HeapDeCommitFreeBlockThreshold = 0x%x\n",
|
||||
offsetof(struct NtPeb, HeapDeCommitFreeBlockThreshold));
|
||||
printf("NumberOfHeaps = 0x%x\n", offsetof(struct NtPeb, NumberOfHeaps));
|
||||
printf("MaximumNumberOfHeaps = 0x%x\n",
|
||||
offsetof(struct NtPeb, MaximumNumberOfHeaps));
|
||||
printf("ProcessHeaps = 0x%x\n", offsetof(struct NtPeb, ProcessHeaps));
|
||||
printf("GdiSharedHandleTable = 0x%x\n",
|
||||
offsetof(struct NtPeb, GdiSharedHandleTable));
|
||||
printf("ProcessStarterHelper = 0x%x\n",
|
||||
offsetof(struct NtPeb, ProcessStarterHelper));
|
||||
printf("GdiDCAttributeList = 0x%x\n",
|
||||
offsetof(struct NtPeb, GdiDCAttributeList));
|
||||
printf("LoaderLock = 0x%x\n", offsetof(struct NtPeb, LoaderLock));
|
||||
printf("OSMajorVersion = 0x%x\n", offsetof(struct NtPeb, OSMajorVersion));
|
||||
printf("OSMinorVersion = 0x%x\n", offsetof(struct NtPeb, OSMinorVersion));
|
||||
printf("OSVersion = 0x%x\n", offsetof(struct NtPeb, OSVersion));
|
||||
printf("OSBuildNumber = 0x%x\n", offsetof(struct NtPeb, OSBuildNumber));
|
||||
printf("OSCSDVersion = 0x%x\n", offsetof(struct NtPeb, OSCSDVersion));
|
||||
printf("OSPlatformId = 0x%x\n", offsetof(struct NtPeb, OSPlatformId));
|
||||
printf("ImageSubsystem = 0x%x\n", offsetof(struct NtPeb, ImageSubsystem));
|
||||
printf("ImageSubsystemMajorVersion = 0x%x\n",
|
||||
offsetof(struct NtPeb, ImageSubsystemMajorVersion));
|
||||
printf("ImageSubsystemMinorVersion = 0x%x\n",
|
||||
offsetof(struct NtPeb, ImageSubsystemMinorVersion));
|
||||
printf("ImageProcessAffinityMask = 0x%x\n",
|
||||
offsetof(struct NtPeb, ImageProcessAffinityMask));
|
||||
printf("ActiveProcessAffinityMask = 0x%x\n",
|
||||
offsetof(struct NtPeb, ActiveProcessAffinityMask));
|
||||
printf("GdiHandleBuffer = 0x%x\n", offsetof(struct NtPeb, GdiHandleBuffer));
|
||||
printf("PostProcessInitRoutine = 0x%x\n",
|
||||
offsetof(struct NtPeb, PostProcessInitRoutine));
|
||||
printf("TlsExpansionBitmap = 0x%x\n",
|
||||
offsetof(struct NtPeb, TlsExpansionBitmap));
|
||||
printf("TlsExpansionBitmapBits = 0x%x\n",
|
||||
offsetof(struct NtPeb, TlsExpansionBitmapBits));
|
||||
printf("SessionId = 0x%x\n", offsetof(struct NtPeb, SessionId));
|
||||
printf("AppCompatFlags = 0x%x\n", offsetof(struct NtPeb, AppCompatFlags));
|
||||
printf("AppCompatFlagsUser = 0x%x\n",
|
||||
offsetof(struct NtPeb, AppCompatFlagsUser));
|
||||
printf("pShimData = 0x%x\n", offsetof(struct NtPeb, pShimData));
|
||||
printf("AppCompatInfo = 0x%x\n", offsetof(struct NtPeb, AppCompatInfo));
|
||||
printf("CSDVersion = 0x%x\n", offsetof(struct NtPeb, CSDVersion));
|
||||
printf("ActivationContextData = 0x%x\n",
|
||||
offsetof(struct NtPeb, ActivationContextData));
|
||||
printf("ProcessAssemblyStorageMap = 0x%x\n",
|
||||
offsetof(struct NtPeb, ProcessAssemblyStorageMap));
|
||||
printf("SystemDefaultActivationContextData = 0x%x\n",
|
||||
offsetof(struct NtPeb, SystemDefaultActivationContextData));
|
||||
printf("SystemAssemblyStorageMap = 0x%x\n",
|
||||
offsetof(struct NtPeb, SystemAssemblyStorageMap));
|
||||
printf("MinimumStackCommit = 0x%x\n",
|
||||
offsetof(struct NtPeb, MinimumStackCommit));
|
||||
return 0;
|
||||
}
|
28
tool/decode/unhex.c
Normal file
28
tool/decode/unhex.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Hex to binary converter program.
|
||||
* Non-hex bytes are ignored. If you've got imposter syndrome you could
|
||||
* call this a compiler and start coding in hex.
|
||||
*/
|
||||
|
||||
int main() {
|
||||
int o, t = -1;
|
||||
while (0 <= (o = getchar()) && o <= 255) {
|
||||
if (!isxdigit(o)) continue;
|
||||
int h = hextoint(o);
|
||||
if (t != -1) putchar(t * 16 + h), h = -1;
|
||||
t = h;
|
||||
}
|
||||
if (ferror(stdout)) return 1;
|
||||
if (t != -1) return 2;
|
||||
return 0;
|
||||
}
|
209
tool/decode/x86opinfo.c
Normal file
209
tool/decode/x86opinfo.c
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#include "tool/decode/lib/xederrors.h"
|
||||
|
||||
const struct IdName kXedModeNames[] = {
|
||||
{XED_MACHINE_MODE_LONG_64, "long"},
|
||||
{XED_MACHINE_MODE_LONG_COMPAT_32, "long32"},
|
||||
{XED_MACHINE_MODE_LONG_COMPAT_16, "long16"},
|
||||
{XED_MACHINE_MODE_LEGACY_32, "legacy"},
|
||||
{XED_MACHINE_MODE_LEGACY_16, "legacy16"},
|
||||
{XED_MACHINE_MODE_REAL, "real"},
|
||||
{XED_MACHINE_MODE_UNREAL, "unreal"},
|
||||
};
|
||||
|
||||
enum XedMachineMode g_mode;
|
||||
struct XedDecodedInst g_xedd;
|
||||
|
||||
noreturn void ShowUsage(int rc, FILE *f) {
|
||||
size_t i;
|
||||
fputs("Usage: ", f);
|
||||
fputs(program_invocation_name, f);
|
||||
fputs(" [-r] [-m MODE] HEX\n MODE ∊ {", f);
|
||||
fputs(kXedModeNames[0].name, f);
|
||||
for (i = 1; i < ARRAYLEN(kXedModeNames); ++i) {
|
||||
fputc(',', f);
|
||||
fputs(kXedModeNames[i].name, f);
|
||||
}
|
||||
fputs("}\n", f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void SetMachineMode(const char *s) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(kXedModeNames); ++i) {
|
||||
if (strcasecmp(s, kXedModeNames[i].name) == 0) {
|
||||
g_mode = kXedModeNames[i].id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fputs("error: bad mode\n", stderr);
|
||||
ShowUsage(EXIT_FAILURE, stderr);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
g_mode = XED_MACHINE_MODE_LONG_64;
|
||||
while ((opt = getopt(argc, argv, "?hrm:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'r':
|
||||
g_mode = XED_MACHINE_MODE_REAL;
|
||||
break;
|
||||
case 'm':
|
||||
SetMachineMode(optarg);
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
ShowUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
ShowUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckHex(const char *s) {
|
||||
size_t i, n;
|
||||
if ((n = strlen(s)) % 2 == 1) {
|
||||
ShowUsage(EX_DATAERR, stderr);
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!isxdigit(s[i + 0])) {
|
||||
ShowUsage(EX_DATAERR, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShowField(const char *name, uint64_t value) {
|
||||
if (value) {
|
||||
printf("/\t%-20s = %#lx\n", name, value);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowOffset(const char *name, uint64_t off) {
|
||||
printf("/\t%-20s = %#lx\n", name, off);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int err;
|
||||
size_t i, j, k;
|
||||
uint8_t buf[XED_MAX_INSTRUCTION_BYTES];
|
||||
|
||||
GetOpts(argc, argv);
|
||||
|
||||
for (k = 0, i = optind; i < argc; ++i) {
|
||||
CheckHex(argv[i]);
|
||||
for (j = 0; argv[i][j]; j += 2) {
|
||||
if (++k > XED_MAX_INSTRUCTION_BYTES) ShowUsage(EX_DATAERR, stderr);
|
||||
buf[k - 1] = hextoint(argv[i][j + 0]) << 4 | hextoint(argv[i][j + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
xed_decoded_inst_zero_set_mode(&g_xedd, g_mode);
|
||||
if ((err = xed_instruction_length_decode(&g_xedd, buf, k)) !=
|
||||
XED_ERROR_NONE) {
|
||||
fputs("XED_ERROR_", stderr);
|
||||
fputs(findnamebyid(kXedErrorNames, err), stderr);
|
||||
fputc('\n', stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define SHOWOP(F) ShowField(#F, g_xedd.operands.F)
|
||||
SHOWOP(amd3dnow);
|
||||
SHOWOP(asz);
|
||||
SHOWOP(bcrc);
|
||||
SHOWOP(chip);
|
||||
SHOWOP(cldemote);
|
||||
SHOWOP(disp);
|
||||
SHOWOP(disp_width);
|
||||
SHOWOP(error);
|
||||
SHOWOP(esrc);
|
||||
SHOWOP(first_f2f3);
|
||||
SHOWOP(has_modrm);
|
||||
SHOWOP(has_sib);
|
||||
SHOWOP(hint);
|
||||
SHOWOP(ild_f2);
|
||||
SHOWOP(ild_f3);
|
||||
SHOWOP(ild_seg);
|
||||
SHOWOP(imm1_bytes);
|
||||
SHOWOP(imm_width);
|
||||
SHOWOP(last_f2f3);
|
||||
SHOWOP(llrc);
|
||||
SHOWOP(lock);
|
||||
SHOWOP(map);
|
||||
SHOWOP(mask);
|
||||
SHOWOP(max_bytes);
|
||||
SHOWOP(mod);
|
||||
SHOWOP(mode);
|
||||
SHOWOP(mode_first_prefix);
|
||||
SHOWOP(modep5);
|
||||
SHOWOP(modep55c);
|
||||
SHOWOP(modrm_byte);
|
||||
SHOWOP(nominal_opcode);
|
||||
SHOWOP(nprefixes);
|
||||
SHOWOP(nrexes);
|
||||
SHOWOP(nseg_prefixes);
|
||||
SHOWOP(osz);
|
||||
SHOWOP(out_of_bytes);
|
||||
SHOWOP(pos_disp);
|
||||
SHOWOP(pos_imm);
|
||||
SHOWOP(pos_imm1);
|
||||
SHOWOP(pos_modrm);
|
||||
SHOWOP(pos_nominal_opcode);
|
||||
SHOWOP(pos_sib);
|
||||
SHOWOP(prefix66);
|
||||
SHOWOP(realmode);
|
||||
SHOWOP(reg);
|
||||
SHOWOP(rep);
|
||||
SHOWOP(rex);
|
||||
SHOWOP(rexb);
|
||||
SHOWOP(rexr);
|
||||
SHOWOP(rexrr);
|
||||
SHOWOP(rexw);
|
||||
SHOWOP(rexx);
|
||||
SHOWOP(rm);
|
||||
SHOWOP(seg_ovd);
|
||||
SHOWOP(sibbase);
|
||||
SHOWOP(sibindex);
|
||||
SHOWOP(sibscale);
|
||||
SHOWOP(srm);
|
||||
SHOWOP(ubit);
|
||||
SHOWOP(uimm0);
|
||||
SHOWOP(uimm1);
|
||||
SHOWOP(vex_prefix);
|
||||
SHOWOP(vexdest210);
|
||||
SHOWOP(vexdest3);
|
||||
SHOWOP(vexdest4);
|
||||
SHOWOP(vexvalid);
|
||||
SHOWOP(vl);
|
||||
SHOWOP(wbnoinvd);
|
||||
SHOWOP(zeroing);
|
||||
|
||||
return 0;
|
||||
}
|
38
tool/decode/xor.c
Normal file
38
tool/decode/xor.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Hex to binary converter program.
|
||||
* Non-hex bytes are ignored. If you've got imposter syndrome you could
|
||||
* call this a compiler and start coding in hex.
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
size_t i, j, l;
|
||||
uint8_t *buf;
|
||||
if (argc == 1) return 1;
|
||||
buf = gc(xmalloc((l = strlen(argv[1]) / 2)));
|
||||
for (j = 0; j < l; ++j) {
|
||||
buf[j] = 0;
|
||||
}
|
||||
for (i = 1; i < argc; ++i) {
|
||||
for (j = 0; j < l; ++j) {
|
||||
buf[j] ^= hextoint(argv[i][j + 0]) << 4 | hextoint(argv[i][j + 1]);
|
||||
}
|
||||
}
|
||||
for (j = 0; j < l; ++j) {
|
||||
putchar("0123456789abcdef"[(buf[j] >> 4) & 0xf]);
|
||||
putchar("0123456789abcdef"[(buf[j] >> 0) & 0xf]);
|
||||
}
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
324
tool/decode/zip.c
Normal file
324
tool/decode/zip.c
Normal file
|
@ -0,0 +1,324 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/zip.h"
|
||||
#include "tool/decode/lib/asmcodegen.h"
|
||||
#include "tool/decode/lib/disassemblehex.h"
|
||||
#include "tool/decode/lib/flagger.h"
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#include "tool/decode/lib/ntfileflagnames.h"
|
||||
#include "tool/decode/lib/titlegen.h"
|
||||
#include "tool/decode/lib/zipnames.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Zip File Disassembler.
|
||||
*/
|
||||
|
||||
nodiscard char *formatdosdate(uint16_t dosdate) {
|
||||
return xasprintf("%04u-%02u-%02u", ((dosdate >> 9) & 0b1111111) + 1980,
|
||||
(dosdate >> 5) & 0b1111, dosdate & 0b11111);
|
||||
}
|
||||
|
||||
nodiscard char *formatdostime(uint16_t dostime) {
|
||||
return xasprintf("%02u:%02u:%02u", (dostime >> 11) & 0b11111,
|
||||
(dostime >> 5) & 0b111111, (dostime << 1) & 0b111110);
|
||||
}
|
||||
|
||||
void advancepos(uint8_t *map, size_t *pos, size_t off) {
|
||||
CHECK_GE(off, *pos);
|
||||
if (off > *pos) {
|
||||
printf("\n/\t<%s>\n", "LIMBO");
|
||||
disassemblehex(&map[*pos], off - *pos, stdout);
|
||||
printf("/\t</%s>\n", "LIMBO");
|
||||
}
|
||||
*pos = off;
|
||||
}
|
||||
|
||||
void showgeneralflag(uint16_t generalflag) {
|
||||
puts("\
|
||||
/ ┌─utf8\n\
|
||||
/ │ ┌─strong encryption\n\
|
||||
/ │ │┌─compressed patch data\n\
|
||||
/ │ ││ ┌─crc and size go after file content\n\
|
||||
/ │ ││ │┌─{normal,max,fast,superfast}\n\
|
||||
/ │ ││ ││ ┌─encrypted\n\
|
||||
/ rrrr│uuuu││r│├┐│");
|
||||
show(".short", format(b1, "0b%016b", generalflag), "generalflag");
|
||||
}
|
||||
|
||||
void showtimestamp(uint16_t time, uint16_t date) {
|
||||
show(".short", format(b1, "%#04hx", time),
|
||||
gc(xasprintf("%s (%s)", "lastmodifiedtime", gc(formatdostime(time)))));
|
||||
show(".short", format(b1, "%#04hx", date),
|
||||
gc(xasprintf("%s (%s)", "lastmodifieddate", gc(formatdosdate(date)))));
|
||||
}
|
||||
|
||||
void showcompressmethod(uint16_t compressmethod) {
|
||||
show(".short",
|
||||
firstnonnull(findnamebyid(kZipCompressionNames, compressmethod),
|
||||
format(b1, "%hu", compressmethod)),
|
||||
"compressionmethod");
|
||||
}
|
||||
|
||||
void showextrantfs(uint8_t *ntfs) {
|
||||
struct timespec mtime, atime, ctime;
|
||||
filetimetotimespec(
|
||||
&mtime, (struct NtFileTime){read32le(ntfs + 8), read32le(ntfs + 12)});
|
||||
filetimetotimespec(
|
||||
&atime, (struct NtFileTime){read32le(ntfs + 16), read32le(ntfs + 20)});
|
||||
filetimetotimespec(
|
||||
&ctime, (struct NtFileTime){read32le(ntfs + 24), read32le(ntfs + 30)});
|
||||
show(".long", gc(xasprintf("%d", read32le(ntfs))), "ntfs reserved");
|
||||
show(".short", gc(xasprintf("0x%04x", read16le(ntfs + 4))),
|
||||
"ntfs attribute tag value #1");
|
||||
show(".short", gc(xasprintf("%hu", read16le(ntfs + 6))),
|
||||
"ntfs attribute tag size");
|
||||
show(".quad", gc(xasprintf("%lu", read64le(ntfs + 8))),
|
||||
gc(xasprintf("%s (%s)", "ntfs last modified time",
|
||||
gc(xiso8601(&mtime)))));
|
||||
show(".quad", gc(xasprintf("%lu", read64le(ntfs + 16))),
|
||||
gc(xasprintf("%s (%s)", "ntfs last access time", gc(xiso8601(&atime)))));
|
||||
show(".quad", gc(xasprintf("%lu", read64le(ntfs + 24))),
|
||||
gc(xasprintf("%s (%s)", "ntfs creation time", gc(xiso8601(&ctime)))));
|
||||
}
|
||||
|
||||
void showextra(uint8_t *extra) {
|
||||
switch (ZIP_EXTRA_HEADERID(extra)) {
|
||||
case kZipExtraNtfs:
|
||||
showextrantfs(ZIP_EXTRA_CONTENT(extra));
|
||||
break;
|
||||
case kZipExtraZip64:
|
||||
/* TODO */
|
||||
default:
|
||||
disassemblehex(ZIP_EXTRA_CONTENT(extra), ZIP_EXTRA_CONTENTSIZE(extra),
|
||||
stdout);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void showexternalattributes(uint8_t *cf) {
|
||||
uint32_t ea;
|
||||
ea = ZIP_CFILE_EXTERNALATTRIBUTES(cf);
|
||||
if (ZIP_CFILE_FILEATTRCOMPAT(cf) == kZipOsUnix) {
|
||||
show(".short", recreateflags(kNtFileFlagNames, ea & 0xffff),
|
||||
"dos file flags");
|
||||
show(".short", format(b1, "%#o", ea >> 16), "st_mode");
|
||||
} else {
|
||||
show(".long", recreateflags(kNtFileFlagNames, ea), "externalattributes");
|
||||
}
|
||||
}
|
||||
|
||||
void showextras(uint8_t *extras, uint16_t extrassize) {
|
||||
int i;
|
||||
bool first;
|
||||
uint8_t *p, *pe;
|
||||
if (extrassize) {
|
||||
first = true;
|
||||
for (p = extras, pe = extras + extrassize, i = 0; p < pe;
|
||||
p += ZIP_EXTRA_SIZE(p), ++i) {
|
||||
show(".short",
|
||||
firstnonnull(findnamebyid(kZipExtraNames, ZIP_EXTRA_HEADERID(p)),
|
||||
gc(xasprintf("0x%04hx", ZIP_EXTRA_HEADERID(p)))),
|
||||
gc(xasprintf("%s[%d].%s", "extras", i, "headerid")));
|
||||
show(".short", gc(xasprintf("%df-%df", (i + 2) * 10, (i + 1) * 10)),
|
||||
gc(xasprintf("%s[%d].%s (%hd %s)", "extras", i, "contentsize",
|
||||
ZIP_EXTRA_CONTENTSIZE(p), "bytes")));
|
||||
if (first) {
|
||||
first = false;
|
||||
printf("%d:", (i + 1) * 10);
|
||||
}
|
||||
showextra(p);
|
||||
printf("%d:", (i + 2) * 10);
|
||||
}
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void showlocalfileheader(uint8_t *lf, uint16_t idx) {
|
||||
printf("\n/\t%s #%hu (%zu %s)\n", "local file", idx + 1,
|
||||
ZIP_LFILE_HDRSIZE(lf), "bytes");
|
||||
show(".ascii", format(b1, "%`'.*s", 4, lf), "magic");
|
||||
show(".byte",
|
||||
firstnonnull(findnamebyid(kZipEraNames, ZIP_LFILE_VERSIONNEED(lf)),
|
||||
gc(xasprintf("%d", ZIP_LFILE_VERSIONNEED(lf)))),
|
||||
"pkzip version need");
|
||||
show(".byte",
|
||||
firstnonnull(findnamebyid(kZipOsNames, ZIP_LFILE_OSNEED(lf)),
|
||||
gc(xasprintf("%d", ZIP_LFILE_OSNEED(lf)))),
|
||||
"os need");
|
||||
showgeneralflag(ZIP_LFILE_GENERALFLAG(lf));
|
||||
showcompressmethod(ZIP_LFILE_COMPRESSIONMETHOD(lf));
|
||||
showtimestamp(ZIP_LFILE_LASTMODIFIEDTIME(lf), ZIP_LFILE_LASTMODIFIEDDATE(lf));
|
||||
show(".long", format(b1, "%#x", ZIP_LFILE_CRC32(lf)),
|
||||
gc(xasprintf(
|
||||
"%s (%#x)", "crc32z",
|
||||
crc32_z(0, ZIP_LFILE_CONTENT(lf), ZIP_LFILE_COMPRESSEDSIZE(lf)))));
|
||||
show(".long", "3f-2f",
|
||||
format(b1, "%s (%u %s)", "compressedsize", ZIP_LFILE_COMPRESSEDSIZE(lf),
|
||||
"bytes"));
|
||||
show(".long", format(b1, "%u", ZIP_LFILE_UNCOMPRESSEDSIZE(lf)),
|
||||
"uncompressedsize");
|
||||
show(".short", "1f-0f",
|
||||
format(b1, "%s (%hu %s)", "namesize", ZIP_LFILE_NAMESIZE(lf), "bytes"));
|
||||
show(
|
||||
".short", "2f-1f",
|
||||
format(b1, "%s (%hu %s)", "extrasize", ZIP_LFILE_EXTRASIZE(lf), "bytes"));
|
||||
printf("0:");
|
||||
show(".ascii",
|
||||
format(b1, "%`'s",
|
||||
gc(strndup(ZIP_LFILE_NAME(lf), ZIP_LFILE_NAMESIZE(lf)))),
|
||||
"name");
|
||||
printf("1:");
|
||||
showextras(ZIP_LFILE_EXTRA(lf), ZIP_LFILE_EXTRASIZE(lf));
|
||||
printf("2:");
|
||||
disassemblehex(ZIP_LFILE_CONTENT(lf), ZIP_LFILE_COMPRESSEDSIZE(lf), stdout);
|
||||
printf("3:\n");
|
||||
}
|
||||
|
||||
void showcentralfileheader(uint8_t *cf) {
|
||||
printf("\n/\t%s (%zu %s)\n", "central directory file header",
|
||||
ZIP_CFILE_HDRSIZE(cf), "bytes");
|
||||
show(".ascii", format(b1, "%`'.*s", 4, cf), "magic");
|
||||
show(".byte", gc(xasprintf("%d", ZIP_CFILE_VERSIONMADE(cf))), "version made");
|
||||
show(".byte",
|
||||
firstnonnull(findnamebyid(kZipOsNames, ZIP_CFILE_FILEATTRCOMPAT(cf)),
|
||||
gc(xasprintf("%d", ZIP_CFILE_FILEATTRCOMPAT(cf)))),
|
||||
"file attr compat");
|
||||
show(".byte",
|
||||
firstnonnull(findnamebyid(kZipEraNames, ZIP_CFILE_VERSIONNEED(cf)),
|
||||
gc(xasprintf("%d", ZIP_CFILE_VERSIONNEED(cf)))),
|
||||
"pkzip version need");
|
||||
show(".byte",
|
||||
firstnonnull(findnamebyid(kZipOsNames, ZIP_CFILE_OSNEED(cf)),
|
||||
gc(xasprintf("%d", ZIP_CFILE_OSNEED(cf)))),
|
||||
"os need");
|
||||
showgeneralflag(ZIP_CFILE_GENERALFLAG(cf));
|
||||
showcompressmethod(ZIP_CFILE_COMPRESSIONMETHOD(cf));
|
||||
showtimestamp(ZIP_CFILE_LASTMODIFIEDTIME(cf), ZIP_CFILE_LASTMODIFIEDDATE(cf));
|
||||
show(".long", format(b1, "%#x", ZIP_CFILE_CRC32(cf)), "crc32z");
|
||||
show(".long", format(b1, "%u", ZIP_CFILE_COMPRESSEDSIZE(cf)),
|
||||
"compressedsize");
|
||||
show(".long", format(b1, "%u", ZIP_CFILE_UNCOMPRESSEDSIZE(cf)),
|
||||
"uncompressedsize");
|
||||
show(".short", "1f-0f",
|
||||
format(b1, "%s (%hu %s)", "namesize", ZIP_CFILE_NAMESIZE(cf), "bytes"));
|
||||
show(
|
||||
".short", "2f-1f",
|
||||
format(b1, "%s (%hu %s)", "extrasize", ZIP_CFILE_EXTRASIZE(cf), "bytes"));
|
||||
show(".short", "3f-2f",
|
||||
format(b1, "%s (%hu %s)", "commentsize", ZIP_CFILE_COMMENTSIZE(cf),
|
||||
"bytes"));
|
||||
show(".short", format(b1, "%hu", ZIP_CFILE_DISK(cf)), "disk");
|
||||
show(".short",
|
||||
recreateflags(kZipIattrNames, ZIP_CFILE_INTERNALATTRIBUTES(cf)),
|
||||
"internalattributes");
|
||||
showexternalattributes(cf);
|
||||
show(".long", format(b1, "%u", ZIP_CFILE_OFFSET(cf)), "lfile hdr offset");
|
||||
printf("0:");
|
||||
show(".ascii",
|
||||
format(b1, "%`'s",
|
||||
gc(strndup(ZIP_CFILE_NAME(cf), ZIP_CFILE_NAMESIZE(cf)))),
|
||||
"name");
|
||||
printf("1:");
|
||||
showextras(ZIP_CFILE_EXTRA(cf), ZIP_CFILE_EXTRASIZE(cf));
|
||||
printf("2:");
|
||||
disassemblehex(ZIP_CFILE_COMMENT(cf), ZIP_CFILE_COMMENTSIZE(cf), stdout);
|
||||
printf("3:\n");
|
||||
}
|
||||
|
||||
void showcentraldirheader(uint8_t *cd) {
|
||||
printf("\n/\t%s (%zu %s)\n", "end of central directory header",
|
||||
ZIP_CDIR_HDRSIZE(cd), "bytes");
|
||||
show(".ascii", format(b1, "%`'.*s", 4, cd), "magic");
|
||||
show(".short", format(b1, "%hd", ZIP_CDIR_DISK(cd)), "disk");
|
||||
show(".short", format(b1, "%hd", ZIP_CDIR_STARTINGDISK(cd)), "startingdisk");
|
||||
show(".short", format(b1, "%hu", ZIP_CDIR_RECORDSONDISK(cd)),
|
||||
"recordsondisk");
|
||||
show(".short", format(b1, "%hu", ZIP_CDIR_RECORDS(cd)), "records");
|
||||
show(".long", format(b1, "%u", ZIP_CDIR_SIZE(cd)), "size");
|
||||
show(".long", format(b1, "%u", ZIP_CDIR_OFFSET(cd)), "cfile hdrs offset");
|
||||
show(".short", "1f-0f",
|
||||
format(b1, "%s (%hu %s)", "commentsize", ZIP_CDIR_COMMENTSIZE(cd),
|
||||
"bytes"));
|
||||
printf("0:");
|
||||
disassemblehex(ZIP_CDIR_COMMENT(cd), ZIP_CDIR_COMMENTSIZE(cd), stdout);
|
||||
printf("1:\n");
|
||||
}
|
||||
|
||||
void disassemblezip(uint8_t *map, size_t mapsize) {
|
||||
size_t pos;
|
||||
uint16_t i;
|
||||
static int records;
|
||||
uint8_t *cd, *cf, *lf;
|
||||
CHECK_NOTNULL((cd = zipfindcentraldir(map, mapsize)));
|
||||
pos = 0;
|
||||
records = ZIP_CDIR_RECORDS(cd);
|
||||
for (i = 0, cf = map + ZIP_CDIR_OFFSET(cd); i < records;
|
||||
++i, cf += ZIP_CFILE_HDRSIZE(cf)) {
|
||||
lf = map + ZIP_CFILE_OFFSET(cf);
|
||||
CHECK_EQ(kZipLfileHdrMagic, ZIP_LFILE_MAGIC(lf));
|
||||
advancepos(map, &pos, lf - map);
|
||||
showlocalfileheader(lf, i);
|
||||
pos = (lf - map) + ZIP_LFILE_SIZE(lf);
|
||||
}
|
||||
for (i = 0, cf = map + ZIP_CDIR_OFFSET(cd); i < records;
|
||||
++i, cf += ZIP_CFILE_HDRSIZE(cf)) {
|
||||
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(cf));
|
||||
advancepos(map, &pos, cf - map);
|
||||
showcentralfileheader(cf);
|
||||
pos = (cf - map) + ZIP_CFILE_HDRSIZE(cf);
|
||||
}
|
||||
advancepos(map, &pos, cd - map);
|
||||
showcentraldirheader(cd);
|
||||
pos = (cd - map) + ZIP_CDIR_HDRSIZE(cd);
|
||||
advancepos(map, &pos, mapsize);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int fd;
|
||||
uint8_t *map;
|
||||
struct stat st;
|
||||
CHECK_EQ(2, argc);
|
||||
CHECK_NE(-1, (fd = open(argv[1], O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_GE(st.st_size, kZipCdirHdrMinSize);
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
showtitle("αcτµαlly pδrταblε εxεcµταblε", "tool/decode/zip",
|
||||
basename(argv[1]), NULL, &kModelineAsm);
|
||||
disassemblezip(map, st.st_size);
|
||||
CHECK_NE(-1, munmap(map, st.st_size));
|
||||
CHECK_NE(-1, close(fd));
|
||||
return 0;
|
||||
}
|
339
tool/emacs/cosmo-asm-mode.el
Normal file
339
tool/emacs/cosmo-asm-mode.el
Normal file
|
@ -0,0 +1,339 @@
|
|||
;; ╔──────────────────────────────────────────────────────────────────╗
|
||||
;; │ To the extent possible under law, Justine Tunney has waived │
|
||||
;; │ all copyright and related or neighboring rights to this file, │
|
||||
;; │ as it is written in the following disclaimers: │
|
||||
;; │ • http://unlicense.org/ │
|
||||
;; │ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
;; ╚──────────────────────────────────────────────────────────────────╝
|
||||
;; Reconfigures GNU Emacs syntax highlighting for GNU Assembler syntax.
|
||||
|
||||
(require 'asm-mode)
|
||||
|
||||
(defun cosmo-regexpify (x)
|
||||
(let ((join (lambda (sep lis)
|
||||
(mapconcat 'identity lis sep))))
|
||||
(cond ((vectorp x)
|
||||
(funcall join "" (mapcar 'cosmo-regexpify x)))
|
||||
((listp x)
|
||||
(concat "\\(?:"
|
||||
(funcall join "\\|" (mapcar 'cosmo-regexpify x))
|
||||
"\\)"))
|
||||
('t x))))
|
||||
|
||||
(defun cosmo-fontify (faces regexp limit predicate)
|
||||
"Set FACES on REGEXP matches until LIMIT that satisfy PREDICATE."
|
||||
(while (re-search-forward regexp limit t)
|
||||
(let (i (face (save-excursion
|
||||
(backward-char)
|
||||
(face-at-point)))
|
||||
(syntax (syntax-ppss)))
|
||||
(when (funcall predicate face syntax)
|
||||
(dolist (i faces)
|
||||
(put-text-property (match-beginning (car i))
|
||||
(match-end (car i))
|
||||
'face
|
||||
(cdr i)))))))
|
||||
|
||||
(defconst asm-mode-gas-qualifiers-regexp
|
||||
(cosmo-regexpify
|
||||
[("comdat"
|
||||
":req"
|
||||
":vararg"
|
||||
["@" ("function"
|
||||
"object"
|
||||
"got"
|
||||
"size"
|
||||
"gotoff"
|
||||
"plt"
|
||||
"pltoff"
|
||||
"gotpcrel"
|
||||
"progbits"
|
||||
"nobits"
|
||||
"init_array"
|
||||
"fini_array")])
|
||||
"\\>"])
|
||||
"GNU Assembler section, relocation, macro param qualifiers.")
|
||||
|
||||
(defconst asm-mode-doctag-regexp
|
||||
(cosmo-regexpify
|
||||
'(["<"
|
||||
("p" "br"
|
||||
"b" "/b"
|
||||
"i" "/i"
|
||||
"pre" "/pre"
|
||||
"h3" "h4" "/h3" "/h4"
|
||||
"ul" "ol" "li" "/ol" "/ul"
|
||||
"dl" "dt" "dd" "/dl"
|
||||
"table" "tr" "td" "th" "td" "/table")
|
||||
">"]
|
||||
["@"
|
||||
("param"
|
||||
"return"
|
||||
"define"
|
||||
"see"
|
||||
"throws"
|
||||
"returnstwice"
|
||||
"fileoverview"
|
||||
"nullable"
|
||||
"noreturn"
|
||||
"domain"
|
||||
"clob"
|
||||
"since"
|
||||
"forcealignargpointer"
|
||||
"mode"
|
||||
"speed"
|
||||
"cost"
|
||||
"todo"
|
||||
"assume"
|
||||
"define"
|
||||
"domain"
|
||||
"code"
|
||||
"note"
|
||||
"protip"
|
||||
"nxbitsafe"
|
||||
"preinitsafe"
|
||||
"asyncsignalsafe"
|
||||
"notasyncsignalsafe"
|
||||
"isa"
|
||||
"sideffect")
|
||||
"\\>"]))
|
||||
"Assembly docstring highlighting in Google Java Style.")
|
||||
|
||||
(defconst asm-mode-x86-prefix-ops-regexp
|
||||
(cosmo-regexpify
|
||||
[(["[lL][oO][cC][kK]\\>[ \t]*"
|
||||
("[mM][oO][vV][sS]"
|
||||
"[aA][dD][dDcC]"
|
||||
"[sS][uUbB][bB]"
|
||||
"[oO][rR]"
|
||||
"[aA][nN][dD]"
|
||||
"[xX][oO][rR]"
|
||||
"[nN][oO][tT]"
|
||||
"[nN][eE][gG]"
|
||||
"[iI][nN][cC]"
|
||||
"[dD][eE][cC]"
|
||||
"[bB][tT][sSrRcC]?"
|
||||
"[xX][aA][dD][dD]"
|
||||
"[xX][cC][hH][gG]"
|
||||
["[cC][mM][pP][xX][cC][hH][gG]" ("8[bB]" "16[bB]") "?"])]
|
||||
["[rR][eE][pP]" ("[eEzZ]" "[nN][eEzZ]") "?\\>[ \t]*"
|
||||
("[mM][oO][vV][sS]"
|
||||
"[sS][tT][oO][sS]"
|
||||
"[sS][cC][aA][sS]"
|
||||
"[cC][mM][pP][sS]"
|
||||
"[nN][oO][pP]"
|
||||
"[rR][eE][tT]"
|
||||
"[iI][nN][sS]"
|
||||
"[oO][uU][tT][sS]")])
|
||||
"[bBwWlLqQ]?\\>"])
|
||||
"Legal high-level 80x86 prefix instruction combinations.")
|
||||
|
||||
(defconst cosmo-asm-font-lock-keywords
|
||||
(append
|
||||
`(;; AT&T Fortran-Style Assembler Comment
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * /heyho
|
||||
;; * //heyho
|
||||
;;
|
||||
;; - Ignored
|
||||
;;
|
||||
;; * /heyho
|
||||
;; * code code //heyho
|
||||
;;
|
||||
("^/.*$" . font-lock-comment-face)
|
||||
|
||||
;; Immediate Argument
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * mov $2,%eax
|
||||
;; * mov $~2+0x2ul,%eax
|
||||
;; * mov $'c,%eax
|
||||
;; * mov $'\n,%eax
|
||||
;;
|
||||
("[ \t]\\$\\(\\(?:'\\(?:'\\|\\s\"\\|\\s\\.\\|.\\)\\|\\(?:0x[[:xdigit:]]+\\|0b[01]+\\|[1-9][0-9]*\\|0[0-7]*\\)\\(?:[fb]\\|u?l?l?\\)\\|[-*/&^|()%<>~+]\\|[_.[:alpha:]][-_.[:alnum:]]*\\)+\\)"
|
||||
1 font-lock-constant-face)
|
||||
|
||||
(cosmo-asm-doctag-keywords)
|
||||
|
||||
;; Static Branch Prediction
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * jnz,pt 1f
|
||||
;; * jnz,pn 1b
|
||||
;;
|
||||
;; - Traditionally Implied
|
||||
;;
|
||||
;; * jnz,pn 1f
|
||||
;; * jnz,pt 1b
|
||||
;;
|
||||
(",p[tn]" . font-lock-keyword-face)
|
||||
|
||||
("\\\\\\(?:@\\|()\\)" . font-lock-function-name-face)
|
||||
("\\\\\\(\\sw\\|_\\|\\.\\)+\\>" . font-lock-variable-name-face)
|
||||
(,asm-mode-x86-prefix-ops-regexp . font-lock-keyword-face)
|
||||
(,(concat "^\\(\\(?:\\sw\\|\\s_\\|\\.\\)+\\):[ \t]*"
|
||||
"\\(\\(?:\\sw\\|\\.\\)+\\)?")
|
||||
(1 font-lock-function-name-face)
|
||||
(2 font-lock-keyword-face nil t))
|
||||
("^\\((\\sw+)\\)?\\s +\\(\\(\\.?\\sw\\|\\s_\\)+\\(\\.\\sw+\\)*\\)"
|
||||
2 font-lock-keyword-face)
|
||||
("^\\(\\.\\(\\sw\\|\\s_\\|\\.\\)+\\)\\>[^:]?"
|
||||
1 font-lock-keyword-face)
|
||||
("^.*?\\*/\\(\\.\\(\\sw\\|\\s_\\|\\.\\)+\\)\\>[^:]?"
|
||||
1 font-lock-keyword-face)
|
||||
|
||||
;; it's complicated
|
||||
(,asm-mode-gas-qualifiers-regexp
|
||||
. font-lock-type-face))
|
||||
|
||||
cpp-font-lock-keywords
|
||||
|
||||
'(;; GNU-Style Assembler Comment (Ltd. 80x86 &c.)
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * #heyho
|
||||
;; * # heyho
|
||||
;; * .org . #heyho
|
||||
;; * .org . ####euhhcue
|
||||
;; * .org .# ###euhhcue
|
||||
;;
|
||||
;; - Ignored
|
||||
;;
|
||||
;; * #if 0
|
||||
;; * #endif
|
||||
;; * .ascii "#heyho"
|
||||
;;
|
||||
("\\(#.*\\)$" 1 font-lock-comment-face)
|
||||
|
||||
("'\\(\\\\?.\\)\\>" 1 font-lock-constant-face)
|
||||
|
||||
;; Register Value
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * %al
|
||||
;; * %eax
|
||||
;;
|
||||
;; - Ignored
|
||||
;;
|
||||
;; * %%al
|
||||
;;
|
||||
("%\\sw+" . font-lock-variable-name-face)
|
||||
|
||||
;; Hexadecimal Literal
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * 0x0123456789abcdef
|
||||
;; * 0XDEADBEEFu
|
||||
;; * -0xdeadbeefULL
|
||||
;;
|
||||
;; - Ignored
|
||||
;;
|
||||
;; * 0x0123456789abcdefg
|
||||
;;
|
||||
("\\b\\(0[xX]\\)[[:xdigit:]]+\\([ulUL]*\\)\\b"
|
||||
(1 font-lock-constant-face)
|
||||
(2 font-lock-constant-face))
|
||||
|
||||
;; Binary Literal
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * 0b0101101101
|
||||
;; * 0B0101101101u
|
||||
;; * -0b0101101101ULL
|
||||
;;
|
||||
;; - Ignored
|
||||
;;
|
||||
;; * 0b012
|
||||
;;
|
||||
("\\b\\(0[bB]\\)[01]+\\([ulUL]*\\)\\b"
|
||||
(1 font-lock-constant-face)
|
||||
(2 font-lock-constant-face))
|
||||
|
||||
;; Octal Literal
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * 01234567
|
||||
;; * 01234567l
|
||||
;; * -01234567ULL
|
||||
;;
|
||||
;; - Ignored
|
||||
;;
|
||||
;; * 012345678
|
||||
;;
|
||||
("\\b\\(0\\)[0-7]+\\([ulUL]*\\)\\b"
|
||||
(1 font-lock-constant-face)
|
||||
(2 font-lock-constant-face))
|
||||
|
||||
;; Decimal Literal
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * 123456789
|
||||
;; * 123456789l
|
||||
;; * -01234567ULL
|
||||
;;
|
||||
;; - Ignored
|
||||
;;
|
||||
;; * 123456789a
|
||||
;; * 123456789aul
|
||||
;;
|
||||
("\\b[1-9][0-9]+\\([ulUL]*\\)\\b"
|
||||
1 font-lock-constant-face)
|
||||
|
||||
;; AT&T Fortran-Style Assembler Comment
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * /heyho
|
||||
;; * //heyho
|
||||
;;
|
||||
;; - Ignored
|
||||
;;
|
||||
;; * /heyho
|
||||
;; * code code //heyho
|
||||
;;
|
||||
("^/.*$" . font-lock-comment-face)
|
||||
|
||||
;; AT&T-Style Directional Label
|
||||
;;
|
||||
;; - Valid
|
||||
;;
|
||||
;; * 1f
|
||||
;; * 99b
|
||||
;;
|
||||
("\\b\\([0-9]+\\)[fb]\\b" 1 font-lock-function-name-face)))
|
||||
"Additional expressions to highlight in Assembler mode.")
|
||||
|
||||
(defun cosmo-asm-doctag-keywords (limit)
|
||||
(cosmo-fontify '((0 . font-lock-constant-face))
|
||||
asm-mode-doctag-regexp
|
||||
limit
|
||||
(lambda (face syntax)
|
||||
(or (memq face '(font-lock-comment-face))
|
||||
(and syntax
|
||||
(nth 4 syntax))))))
|
||||
|
||||
(defun cosmo-asm-supplemental-hook ()
|
||||
"GNU Assembly in Bell Laboratories Style."
|
||||
(setq asm-comment-char ?¯) ;; Was ESR using TASM?
|
||||
(font-lock-add-keywords 'asm-mode
|
||||
'((cosmo-asm-doctag-keywords))
|
||||
'append)
|
||||
(set (make-local-variable 'require-final-newline) nil)
|
||||
(set (make-local-variable 'indent-tabs-mode) t)
|
||||
(set (make-local-variable 'tab-width) 8))
|
||||
|
||||
(progn
|
||||
(add-hook 'asm-mode-hook 'cosmo-asm-supplemental-hook)
|
||||
(setq asm-font-lock-keywords cosmo-asm-font-lock-keywords))
|
||||
|
||||
(provide 'cosmo-asm-mode)
|
1340
tool/emacs/cosmo-c-builtins.el
Normal file
1340
tool/emacs/cosmo-c-builtins.el
Normal file
File diff suppressed because it is too large
Load diff
232
tool/emacs/cosmo-c-constants.el
Normal file
232
tool/emacs/cosmo-c-constants.el
Normal file
|
@ -0,0 +1,232 @@
|
|||
(defconst cosmo-c-constants-regex
|
||||
(let (
|
||||
|
||||
(c11-constants
|
||||
'("__func__"
|
||||
"__STDC_IEC_559__"
|
||||
"__VA_ARGS__"
|
||||
"__FILE__"
|
||||
"__LINE__"
|
||||
"__DATE__"
|
||||
"__STDC__"
|
||||
"__STDC_HOSTED__"
|
||||
"__STDC_VERSION__"
|
||||
"__TIME__"
|
||||
"__STDC_ISO_10646__"
|
||||
"__STDC_MB_MIGHT_NEQ_WC__"
|
||||
"__STDC_UTF_16__"
|
||||
"__STDC_UTF_32__"
|
||||
"__STDC_ANALYZABLE__"
|
||||
"__STDC_IEC_559_COMPLEX__"
|
||||
"__STDC_LIB_EXT1__"
|
||||
"__STDC_NO_ATOMICS__"
|
||||
"__STDC_NO_COMPLEX__"
|
||||
"__STDC_NO_THREADS__"
|
||||
"__STDC_NO_VLA__"
|
||||
"__STDC_WANT_LIB_EXT1__"))
|
||||
|
||||
(gcc-cpp-412-constants
|
||||
'("__BASE_FILE__"
|
||||
"__CHAR_BIT__"
|
||||
"__FUNCTION__"
|
||||
"__GNUC_MINOR__"
|
||||
"__GNUC_PATCHLEVEL__"
|
||||
"__GNUC__"
|
||||
"__GNUG__"
|
||||
"__INCLUDE_LEVEL__"
|
||||
"__INTMAX_MAX__"
|
||||
"__INT_MAX__"
|
||||
"__LONG_LONG_MAX__"
|
||||
"__LONG_MAX__"
|
||||
"__SCHAR_MAX__"
|
||||
"__SHRT_MAX__"
|
||||
"__DBL_MIN__"
|
||||
"__DBL_MAX__"
|
||||
"__FLT_MIN__"
|
||||
"__FLT_MAX__"
|
||||
"__WCHAR_MAX__"
|
||||
"__WCHAR_UNSIGNED__"))
|
||||
|
||||
(gcc-cpp-92-constants
|
||||
'("__x86_64__"
|
||||
"__amd64__"
|
||||
"__WINT_MAX__"
|
||||
"__BIGGEST_ALIGNMENT__"
|
||||
"__SIZE_MAX__"
|
||||
"__PTRDIFF_MAX__"
|
||||
"__UINTMAX_MAX__"
|
||||
"__SIG_ATOMIC_MAX__"
|
||||
"__INT8_MAX__"
|
||||
"__INT16_MAX__"
|
||||
"__INT32_MAX__"
|
||||
"__INT64_MAX__"
|
||||
"__UINT8_MAX__"
|
||||
"__UINT16_MAX__"
|
||||
"__UINT32_MAX__"
|
||||
"__UINT64_MAX__"
|
||||
"__INT_LEAST8_MAX__"
|
||||
"__INT_LEAST16_MAX__"
|
||||
"__INT_LEAST32_MAX__"
|
||||
"__INT_LEAST64_MAX__"
|
||||
"__UINT_LEAST8_MAX__"
|
||||
"__UINT_LEAST16_MAX__"
|
||||
"__UINT_LEAST32_MAX__"
|
||||
"__UINT_LEAST64_MAX__"
|
||||
"__INT_FAST8_MAX__"
|
||||
"__INT_FAST16_MAX__"
|
||||
"__INT_FAST32_MAX__"
|
||||
"__INT_FAST64_MAX__"
|
||||
"__UINT_FAST8_MAX__"
|
||||
"__UINT_FAST16_MAX__"
|
||||
"__UINT_FAST32_MAX__"
|
||||
"__UINT_FAST64_MAX__"
|
||||
"__INTPTR_MAX__"
|
||||
"__UINTPTR_MAX__"
|
||||
"__WCHAR_MIN__"
|
||||
"__WINT_MIN__"
|
||||
"__SIG_ATOMIC_MIN__"
|
||||
"__SCHAR_WIDTH__"
|
||||
"__SHRT_WIDTH__"
|
||||
"__INT_WIDTH__"
|
||||
"__LONG_WIDTH__"
|
||||
"__LONG_LONG_WIDTH__"
|
||||
"__PTRDIFF_WIDTH__"
|
||||
"__SIG_ATOMIC_WIDTH__"
|
||||
"__SIZE_WIDTH__"
|
||||
"__WCHAR_WIDTH__"
|
||||
"__WINT_WIDTH__"
|
||||
"__INT_LEAST8_WIDTH__"
|
||||
"__INT_LEAST16_WIDTH__"
|
||||
"__INT_LEAST32_WIDTH__"
|
||||
"__INT_LEAST64_WIDTH__"
|
||||
"__INT_FAST8_WIDTH__"
|
||||
"__INT_FAST16_WIDTH__"
|
||||
"__INT_FAST32_WIDTH__"
|
||||
"__INT_FAST64_WIDTH__"
|
||||
"__INTPTR_WIDTH__"
|
||||
"__INTMAX_WIDTH__"
|
||||
"__SIZEOF_INT__"
|
||||
"__SIZEOF_INTMAX__"
|
||||
"__SIZEOF_UINTMAX__"
|
||||
"__SIZEOF_LONG__"
|
||||
"__SIZEOF_LONG_LONG__"
|
||||
"__SIZEOF_SHORT__"
|
||||
"__SIZEOF_POINTER__"
|
||||
"__SIZEOF_FLOAT__"
|
||||
"__SIZEOF_DOUBLE__"
|
||||
"__SIZEOF_LONG_DOUBLE__"
|
||||
"__SIZEOF_SIZE_T__"
|
||||
"__SIZEOF_WCHAR_T__"
|
||||
"__SIZEOF_WINT_T__"
|
||||
"__SIZEOF_PTRDIFF_T__"
|
||||
"__TIMESTAMP__"))
|
||||
|
||||
(limits
|
||||
'("SIZEOF_SHORT"
|
||||
"SIZEOF_INT"
|
||||
"SIZEOF_LONG"
|
||||
"SIZEOF_LONG_LONG"
|
||||
"SIZEOF_POINTER"
|
||||
"SIZEOF_PTRDIFF_T"
|
||||
"SIZEOF_SIZE_T"
|
||||
"SIZEOF_WCHAR_T"
|
||||
"SIZEOF_WINT_T"
|
||||
"SIZEOF_FLOAT"
|
||||
"SIZEOF_FLOAT128"
|
||||
"SIZEOF_DOUBLE"
|
||||
"SIZEOF_FLOAT80"
|
||||
"SIZEOF_LONG_DOUBLE"
|
||||
"SIZEOF_INTMAX"
|
||||
"SCHAR_MAX"
|
||||
"SHRT_MAX"
|
||||
"INT_MAX"
|
||||
"LONG_MAX"
|
||||
"LLONG_MAX"
|
||||
"LONG_LONG_MAX"
|
||||
"SIZE_MAX"
|
||||
"INT8_MAX"
|
||||
"INT16_MAX"
|
||||
"INT32_MAX"
|
||||
"INT64_MAX"
|
||||
"WINT_MAX"
|
||||
"WCHAR_MAX"
|
||||
"INTPTR_MAX"
|
||||
"PTRDIFF_MAX"
|
||||
"SCHAR_MIN"
|
||||
"SHRT_MIN"
|
||||
"UINT_MIN"
|
||||
"INT_MIN"
|
||||
"LONG_MIN"
|
||||
"LLONG_MIN"
|
||||
"LONG_LONG_MIN"
|
||||
"SIZE_MIN"
|
||||
"INT8_MIN"
|
||||
"INT16_MIN"
|
||||
"INT32_MIN"
|
||||
"INT64_MIN"
|
||||
"INTMAX_MIN"
|
||||
"INTPTR_MIN"
|
||||
"WINT_MIN"
|
||||
"WCHAR_MIN"
|
||||
"PTRDIFF_MIN"
|
||||
"USHRT_MAX"
|
||||
"UINT_MAX"
|
||||
"ULONG_MAX"
|
||||
"ULLONG_MAX"
|
||||
"ULONG_LONG_MAX"
|
||||
"UINTPTR_MAX"
|
||||
"UINT8_MAX"
|
||||
"UINT16_MAX"
|
||||
"UINT32_MAX"
|
||||
"UINT64_MAX"
|
||||
"USHRT_MIN"
|
||||
"ULONG_MIN"
|
||||
"ULLONG_MIN"
|
||||
"ULONG_LONG_MIN"
|
||||
"UINT8_MIN"
|
||||
"UINT16_MIN"
|
||||
"UINT32_MIN"
|
||||
"UINT64_MIN"
|
||||
"UINTMAX_MIN"
|
||||
"UINTPTR_MIN"
|
||||
"MB_CUR_MAX"
|
||||
"MB_LEN_MAX"
|
||||
"INTMAX_MAX"
|
||||
"UINTMAX_MAX"
|
||||
"INTMAX_MAX"
|
||||
"UINTMAX_MAX"
|
||||
"DBL_MIN"
|
||||
"DBL_MAX"
|
||||
"FLT_MIN"
|
||||
"FLT_MAX"))
|
||||
|
||||
(cosmopolitan-constants
|
||||
'("__SAUCE__"
|
||||
"PAGESIZE"
|
||||
"FRAMESIZE"
|
||||
"BIGPAGESIZE"
|
||||
"ENV_MAX"
|
||||
"ARG_MAX"
|
||||
"CMD_MAX"
|
||||
"PATH_MAX"
|
||||
"BUFSIZ"
|
||||
"CACHELINE"
|
||||
"CHAR_BIT"
|
||||
"NAME_MAX"
|
||||
"NSIG"
|
||||
"CHILD_MAX"
|
||||
"OPEN_MAX"
|
||||
"ATEXIT_MAX"
|
||||
"__x86__"
|
||||
"__i386__"))
|
||||
|
||||
)
|
||||
(concat "\\_<"
|
||||
(regexp-opt (append c11-constants
|
||||
gcc-cpp-412-constants
|
||||
gcc-cpp-92-constants
|
||||
cosmopolitan-constants
|
||||
limits))
|
||||
"\\_>")))
|
||||
|
||||
(provide 'cosmo-c-constants)
|
315
tool/emacs/cosmo-c-keywords.el
Normal file
315
tool/emacs/cosmo-c-keywords.el
Normal file
|
@ -0,0 +1,315 @@
|
|||
(defconst cosmo-c-keywords-regex
|
||||
(let (
|
||||
|
||||
;; (kar
|
||||
;; '("case"
|
||||
;; "do"
|
||||
;; "return"
|
||||
;; "struct"
|
||||
;; "for"
|
||||
;; "default"
|
||||
;; "auto"
|
||||
;; "while"
|
||||
;; "else"
|
||||
;; "break"
|
||||
;; "union"
|
||||
;; "switch"
|
||||
;; "continue"
|
||||
;; "extern"
|
||||
;; "sizeof"
|
||||
;; "if"
|
||||
;; "goto"))
|
||||
|
||||
;; (ansi
|
||||
;; '("static"
|
||||
;; "sizeof"
|
||||
;; "if"
|
||||
;; "typedef"
|
||||
;; "const"
|
||||
;; "struct"
|
||||
;; "for"
|
||||
;; "union"
|
||||
;; "switch"
|
||||
;; "volatile"
|
||||
;; "do"
|
||||
;; "return"
|
||||
;; "goto"
|
||||
;; "auto"
|
||||
;; "enum"
|
||||
;; "else"
|
||||
;; "break"
|
||||
;; "extern"
|
||||
;; "case"
|
||||
;; "default"
|
||||
;; "register"
|
||||
;; "while"
|
||||
;; "continue"))
|
||||
|
||||
(c99
|
||||
'("inline"
|
||||
"restrict"
|
||||
"_Imaginary"
|
||||
"_Bool"
|
||||
"_Pragma"
|
||||
"_Complex"))
|
||||
|
||||
(c11
|
||||
'("_Atomic"
|
||||
"_Alignas"
|
||||
"_Alignof"
|
||||
"_Noreturn"
|
||||
"_Generic"
|
||||
"_Thread_local"
|
||||
"_Static_assert"
|
||||
"_Complex_I"
|
||||
"_Imaginary_I"))
|
||||
|
||||
;; (cxx17
|
||||
;; '("this"
|
||||
;; "thread_local"
|
||||
;; "private"
|
||||
;; "catch"
|
||||
;; "export"
|
||||
;; "operator"
|
||||
;; "sizeof"
|
||||
;; "dynamic_cast"
|
||||
;; "static_assert"
|
||||
;; "const_cast"
|
||||
;; "const"
|
||||
;; "for"
|
||||
;; "static_cast"
|
||||
;; "union"
|
||||
;; "namespace"
|
||||
;; "switch"
|
||||
;; "virtual"
|
||||
;; "class"
|
||||
;; "alignas"
|
||||
;; "continue"
|
||||
;; "volatile"
|
||||
;; "template"
|
||||
;; "mutable"
|
||||
;; "if"
|
||||
;; "public"
|
||||
;; "friend"
|
||||
;; "do"
|
||||
;; "inline"
|
||||
;; "return"
|
||||
;; "goto"
|
||||
;; "alignof"
|
||||
;; "auto"
|
||||
;; "enum"
|
||||
;; "typedef"
|
||||
;; "else"
|
||||
;; "break"
|
||||
;; "constexpr"
|
||||
;; "new"
|
||||
;; "extern"
|
||||
;; "using"
|
||||
;; "throw"
|
||||
;; "asm"
|
||||
;; "case"
|
||||
;; "typeid"
|
||||
;; "decltype"
|
||||
;; "reinterpret_cast"
|
||||
;; "default"
|
||||
;; "noexcept"
|
||||
;; "register"
|
||||
;; "nullptr"
|
||||
;; "try"
|
||||
;; "typename"
|
||||
;; "while"
|
||||
;; "protected"
|
||||
;; "static"
|
||||
;; "explicit"
|
||||
;; "delete"))
|
||||
|
||||
(cosmo
|
||||
'("__rbx"
|
||||
"__msabi"
|
||||
"microarchitecture"
|
||||
"targetclones"
|
||||
"winstruct"
|
||||
"testonly"
|
||||
"forcealignargpointer"
|
||||
"textexit"
|
||||
"externinline"
|
||||
"noinline"
|
||||
"donothing"
|
||||
"byanymeansnecessary"
|
||||
"threadlocal"
|
||||
"printfesque"
|
||||
"flattenout"
|
||||
"mallocesque"
|
||||
"vallocesque"
|
||||
"null"
|
||||
"paramsnonnull"
|
||||
"returnspointerwithnoaliases"
|
||||
"alignas"
|
||||
"nosideeffect"
|
||||
"decltype"
|
||||
"forceinline"
|
||||
"nocallersavedregisters"
|
||||
"nothrow"
|
||||
"nooptimize"
|
||||
"optimizesize"
|
||||
"optimizespeed"
|
||||
"alignof"
|
||||
"relegated"
|
||||
"antiquity"
|
||||
"memcpyesque"
|
||||
"libcesque"
|
||||
"artificial"
|
||||
"returnstwice"
|
||||
"returnsaligned"
|
||||
"noprune"
|
||||
"reallocesque"
|
||||
"nullterminated"
|
||||
"unreachable"
|
||||
"hidden"
|
||||
"privileged"
|
||||
"hasatleast"
|
||||
"nodebuginfo"
|
||||
"frownedupon"
|
||||
"noreturn"
|
||||
"initarray"
|
||||
"mayalias"
|
||||
"noinstrument"
|
||||
"interruptfn"
|
||||
"nocallback"
|
||||
"textstartup"
|
||||
"warnifused"
|
||||
"attributeallocsize"
|
||||
"attributeallocalign"
|
||||
"nodiscard"
|
||||
"nointerpose"
|
||||
"compatfn"
|
||||
"returnsnonnull"
|
||||
"strftimeesque"
|
||||
"firstclass"
|
||||
"preinitarray"
|
||||
"scanfesque"
|
||||
"pureconst"
|
||||
"thatispacked"
|
||||
"strlenesque"
|
||||
"textwindows"
|
||||
"aligned"
|
||||
"typeof"
|
||||
"textreal"
|
||||
"autotype"
|
||||
"_Section"
|
||||
"_Vector_size"))
|
||||
|
||||
(gnu
|
||||
'("__inline"
|
||||
"__alignof"
|
||||
"__typeof"
|
||||
"__restrict"
|
||||
"__const__"
|
||||
"__label__"
|
||||
"__noinline__"
|
||||
"__noclone__"
|
||||
"__force_align_arg_pointer__"
|
||||
"__always_inline__"
|
||||
"__gnu_inline__"
|
||||
"__alignof__"
|
||||
"__asm__"
|
||||
"__attribute__"
|
||||
"__auto_type"
|
||||
"__byte__"
|
||||
"__complex__"
|
||||
"__imag__"
|
||||
"__may_alias__"
|
||||
"__noreturn__"
|
||||
"__packed__"
|
||||
"__pointer__"
|
||||
"__printf__"
|
||||
"__real__"
|
||||
"__restrict__"
|
||||
"__scanf__"
|
||||
"__strfmon__"
|
||||
"__strftime__"
|
||||
"__strong__"
|
||||
"__target__"
|
||||
"__transparent_union__"
|
||||
"__typeof__"
|
||||
"__volatile__"
|
||||
"__word__"
|
||||
"__alias__"
|
||||
"__aligned__"
|
||||
"__alloc_align__"
|
||||
"__alloc_size__"
|
||||
"__artificial__"
|
||||
"__assume_aligned__"
|
||||
"__cold__"
|
||||
"__constructor__"
|
||||
"__destructor__"
|
||||
"__copy__"
|
||||
"__deprecated__"
|
||||
"__error__"
|
||||
"__warning__"
|
||||
"__externally_visible__"
|
||||
"__flatten__"
|
||||
"__format__"
|
||||
"__gnu_format__"
|
||||
"__gnu_printf__"
|
||||
"__gnu_scanf__"
|
||||
"__format_arg__"
|
||||
"__hot__"
|
||||
"__ifunc__"
|
||||
"__interrupt__"
|
||||
"__interrupt_handler__"
|
||||
"__leaf__"
|
||||
"__no_caller_saved_registers__"
|
||||
"__malloc__"
|
||||
"__no_icf__"
|
||||
"__no_instrument_function__"
|
||||
"__no_profile_instrument_function__"
|
||||
"__no_reorder__"
|
||||
"__no_sanitize__"
|
||||
"__no_sanitize_address__"
|
||||
"__no_address_safety_analysis__"
|
||||
"__no_sanitize_thread__"
|
||||
"__leaf__"
|
||||
"__no_sanitize_undefined__"
|
||||
"__no_split_stack__"
|
||||
"__no_stack_limit__"
|
||||
"__noclone__"
|
||||
"__noipa__"
|
||||
"__nonnull__"
|
||||
"__noplt__"
|
||||
"__nothrow__"
|
||||
"__optimize__"
|
||||
"__pure__"
|
||||
"__patchable_function_entry__"
|
||||
"__returns_nonnull__"
|
||||
"__returns_twice__"
|
||||
"__section__"
|
||||
"__sentinel__"
|
||||
"__simd__"
|
||||
"__target_clones__"
|
||||
"__unused__"
|
||||
"__used__"
|
||||
"__visibility__"
|
||||
"__warn_unused_result__"
|
||||
"__params_nonnull__"
|
||||
"__weak__"
|
||||
"__vector_size__"
|
||||
"__mode__"))
|
||||
|
||||
(clang
|
||||
'("__optnone__"
|
||||
"__nodebug__"))
|
||||
|
||||
)
|
||||
(concat "\\_<"
|
||||
(regexp-opt (append ;; kar
|
||||
;; ansi
|
||||
;; c99
|
||||
c11
|
||||
;; cxx17
|
||||
gnu
|
||||
clang
|
||||
cosmo))
|
||||
"\\_>")))
|
||||
|
||||
(provide 'cosmo-c-keywords)
|
222
tool/emacs/cosmo-c-types.el
Normal file
222
tool/emacs/cosmo-c-types.el
Normal file
|
@ -0,0 +1,222 @@
|
|||
(defconst cosmo-c-types-regex
|
||||
(let (
|
||||
|
||||
;; (kar
|
||||
;; '("short unsigned int"
|
||||
;; "int"
|
||||
;; "long unsigned int"
|
||||
;; "char"
|
||||
;; "long"
|
||||
;; "long signed int"
|
||||
;; "signed long"
|
||||
;; "unsigned short int"
|
||||
;; "short int"
|
||||
;; "signed short int"
|
||||
;; "unsigned"
|
||||
;; "long unsigned"
|
||||
;; "unsigned short"
|
||||
;; "short signed int"
|
||||
;; "short unsigned"
|
||||
;; "unsigned char"
|
||||
;; "signed int"
|
||||
;; "unsigned long"
|
||||
;; "long int"
|
||||
;; "unsigned int"
|
||||
;; "signed short"
|
||||
;; "unsigned long int"
|
||||
;; "short signed"
|
||||
;; "signed long int"
|
||||
;; "signed char"
|
||||
;; "long signed"))
|
||||
|
||||
(ansi
|
||||
'("size_t"
|
||||
"wint_t"
|
||||
;; "void"
|
||||
"wchar_t"
|
||||
;; "long double"
|
||||
))
|
||||
|
||||
;; (kar
|
||||
;; '("char"
|
||||
;; "short"
|
||||
;; "int"
|
||||
;; "long"
|
||||
;; "signed"
|
||||
;; "unsigned"))
|
||||
|
||||
;; (ansi
|
||||
;; '("size_t"
|
||||
;; "wint_t"
|
||||
;; "void"
|
||||
;; "wchar_t"))
|
||||
|
||||
(c99
|
||||
'("bool"
|
||||
"_Bool"
|
||||
"unsigned long long int"
|
||||
"int32_t"
|
||||
"uint_least64_t"
|
||||
"long long signed"
|
||||
"intptr_t"
|
||||
"uintmax_t"
|
||||
"long long unsigned int"
|
||||
"int_fast32_t"
|
||||
"int16_t"
|
||||
"int64_t"
|
||||
"int_fast16_t"
|
||||
"int_fast64_t"
|
||||
"errno_t"
|
||||
"uint_fast32_t"
|
||||
"int_least8_t"
|
||||
"uint_least16_t"
|
||||
"long long signed int"
|
||||
"long long"
|
||||
"char16_t"
|
||||
"uint_least32_t"
|
||||
"int_least64_t"
|
||||
"int_least16_t"
|
||||
"int_fast8_t"
|
||||
"uint_least8_t"
|
||||
"uintptr_t"
|
||||
"ssize_t"
|
||||
"long long int"
|
||||
"unsigned long long"
|
||||
"int8_t"
|
||||
"long long unsigned"
|
||||
"signed long long int"
|
||||
"int_least32_t"
|
||||
"uint8_t"
|
||||
"uint_fast64_t"
|
||||
"intmax_t"
|
||||
"uint_fast16_t"
|
||||
"signed long long"
|
||||
"uint32_t"
|
||||
"ptrdiff_t"
|
||||
"char32_t"
|
||||
"uint64_t"
|
||||
"uint16_t"
|
||||
"uint_fast8_t"
|
||||
"complex float"
|
||||
"complex double"
|
||||
"complex long double"))
|
||||
|
||||
(c11
|
||||
'("atomic_uintptr_t"
|
||||
"atomic_uchar"
|
||||
"atomic_int_least32_t"
|
||||
"atomic_uint_least64_t"
|
||||
"atomic_int_fast32_t"
|
||||
"atomic_uint_least16_t"
|
||||
"atomic_short"
|
||||
"atomic_size_t"
|
||||
"atomic_uint"
|
||||
"atomic_char16_t"
|
||||
"atomic_ullong"
|
||||
"atomic_uint_fast16_t"
|
||||
"atomic_int_fast8_t"
|
||||
"atomic_uint_least32_t"
|
||||
"atomic_ptrdiff_t"
|
||||
"atomic_uintmax_t"
|
||||
"atomic_int_least16_t"
|
||||
"atomic_long"
|
||||
"atomic_int"
|
||||
"atomic_int_fast16_t"
|
||||
"atomic_uint_least8_t"
|
||||
"atomic_ushort"
|
||||
"atomic_int_least8_t"
|
||||
"atomic_ulong"
|
||||
"atomic_char32_t"
|
||||
"atomic_schar"
|
||||
"atomic_intmax_t"
|
||||
"atomic_int_least64_t"
|
||||
"atomic_uint_fast64_t"
|
||||
"atomic_wchar_t"
|
||||
"atomic_uint_fast8_t"
|
||||
"atomic_int_fast64_t"
|
||||
"atomic_llong"
|
||||
"atomic_bool"
|
||||
"atomic_intptr_t"
|
||||
"atomic_uint_fast32_t"
|
||||
"atomic_char"))
|
||||
|
||||
(gnu
|
||||
'("__int128"
|
||||
"unsigned __int128"
|
||||
"signed __int128"
|
||||
"_Float16"
|
||||
"_Complex _Float16"
|
||||
"_Float16x"
|
||||
"_Complex _Float16x"
|
||||
"_Float32"
|
||||
"_Complex _Float32"
|
||||
"_Float32x"
|
||||
"_Complex _Float32x"
|
||||
"_Float64"
|
||||
"_Complex _Float64"
|
||||
"_Float64x"
|
||||
"_Complex _Float64x"
|
||||
"_Float128"
|
||||
"_Complex _Float128"))
|
||||
|
||||
(cxx17
|
||||
'())
|
||||
|
||||
(cosmo
|
||||
'("int_least128_t"
|
||||
"int_fast128_t"
|
||||
"bool32"
|
||||
"int128_t"
|
||||
"uint128_t"
|
||||
"axdx_t"))
|
||||
|
||||
(x86intrin
|
||||
'("__v8hu"
|
||||
"__v16qi"
|
||||
"__v4su"
|
||||
"__v8su"
|
||||
"__v16qu"
|
||||
"__v16qs"
|
||||
"__v8hi"
|
||||
"__v4hi"
|
||||
"__v2df"
|
||||
"__v2di"
|
||||
"__v4si"
|
||||
"__v8si"
|
||||
"__m1"
|
||||
"__v2du"
|
||||
"__m2"
|
||||
"__v1di"
|
||||
"__v4sf"
|
||||
"__v8sf"
|
||||
"__v2si"
|
||||
"__m64"
|
||||
"__v2sf"
|
||||
"__v8qi"
|
||||
"__v32qi"
|
||||
"__m128"
|
||||
"__m128d"
|
||||
"__m128i"
|
||||
"__m128_u"
|
||||
"__m128d_u"
|
||||
"__m128i_u"
|
||||
"__m256"
|
||||
"__m256d"
|
||||
"__m256i"
|
||||
"__m256_u"
|
||||
"__m256d_u"
|
||||
"__m256i_u"))
|
||||
|
||||
)
|
||||
(concat "\\_<"
|
||||
(regexp-opt (append ;; kar
|
||||
ansi
|
||||
c99
|
||||
c11
|
||||
gnu
|
||||
cxx17
|
||||
cosmo
|
||||
x86intrin))
|
||||
"\\_>")))
|
||||
|
||||
(provide 'cosmo-c-types)
|
132
tool/emacs/cosmo-format.el
Normal file
132
tool/emacs/cosmo-format.el
Normal file
|
@ -0,0 +1,132 @@
|
|||
;;; cosmo-format.el --- Cosmopolitan Clang-Format Integration
|
||||
|
||||
;; Author: Justine Tunney <jtunney@gmail.com>
|
||||
;; Version: 0.1.0
|
||||
;; License: Public Domain
|
||||
;; Keywords: c c++ clang
|
||||
|
||||
;; To the extent possible under law, Justine Tunney has waived all
|
||||
;; copyright and related or neighboring rights to this file, as it is
|
||||
;; written in the following disclaimers: <http://unlicense.org/> and
|
||||
;; <http://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This module automates indentation, whitespace, and other stylistic
|
||||
;; concerns while editing C/C++ source files. The clang-format program,
|
||||
;; if present on the system, is run each time a buffer is saved.
|
||||
|
||||
;;; Installation:
|
||||
;;
|
||||
;; Put the following in your .emacs.d/init.el file:
|
||||
;;
|
||||
;; (require 'cosmo-format)
|
||||
;;
|
||||
;; Put this file in the root of your project:
|
||||
;;
|
||||
;; printf '---\nBasedOnStyle: Google\n...\n' >.clang-format
|
||||
;;
|
||||
;; Any buffer whose pathname matches `cosmo-format-path-regex' will
|
||||
;; be formatted automatically on save if:
|
||||
;;
|
||||
;; 1. It's able to find the clang-format program, or
|
||||
;; `cosmo-format-bin' is customized.
|
||||
;;
|
||||
;; 2. There's a .clang-format file up the directory tree, or
|
||||
;; `cosmo-format-arg' is customized; in which case, it is
|
||||
;; recommended that it be customized buffer locally.
|
||||
;;
|
||||
;; For all other cases, there are no latency penalties (i.e. superfluous
|
||||
;; i/o syscalls) or risks to leaving this enabled globally.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defcustom cosmo-format-bin nil
|
||||
"Explicit command or pathname of clang-format program."
|
||||
:type 'string
|
||||
:group 'cosmo-format)
|
||||
|
||||
(defcustom cosmo-format-arg nil
|
||||
"Explicit argument to clang-format program."
|
||||
:type 'string
|
||||
:group 'cosmo-format)
|
||||
|
||||
(defcustom cosmo-format-modes '(c-mode
|
||||
c++-mode
|
||||
java-mode
|
||||
protobuf-mode)
|
||||
"List of major-modes that need clang-format."
|
||||
:type '(repeat symbol)
|
||||
:group 'cosmo-format)
|
||||
|
||||
(defcustom cosmo-format-exts '("c" "cc" "h" "inc" ;; c/c++
|
||||
"hh" "cpp" "hpp" ;; ms c/c++
|
||||
"rl" ;; ragel
|
||||
"proto") ;; protobuf
|
||||
"List of pathname extensions that need clang-format."
|
||||
:type '(repeat string)
|
||||
:group 'cosmo-format)
|
||||
|
||||
(defcustom cosmo-format-blacklist '()
|
||||
"List of files to ignore, matched by basename."
|
||||
:type '(repeat string)
|
||||
:group 'cosmo-format)
|
||||
|
||||
(defvar cosmo--clang-format-bin)
|
||||
|
||||
(defmacro cosmo-memoize (var mvar form)
|
||||
"Return VAR or evaluate FORM memoized locally to MVAR."
|
||||
`(cond (,var ,var)
|
||||
((fboundp (quote ,mvar))
|
||||
(cond ((eq ,mvar 'null) nil)
|
||||
(t ,mvar)))
|
||||
(t (let ((res ,form))
|
||||
(setq-local ,mvar (or res 'null))
|
||||
res))))
|
||||
|
||||
(defun cosmo--find-clang-format-bin ()
|
||||
(cosmo-memoize cosmo-format-bin
|
||||
cosmo--clang-format-bin
|
||||
(or (executable-find "clang-format-10")
|
||||
(executable-find "clang-format-9")
|
||||
(executable-find "clang-format-8")
|
||||
(executable-find "clang-format-7")
|
||||
(executable-find "clang-format"))))
|
||||
|
||||
(defun cosmo-format ()
|
||||
"Beautifies source code in current buffer."
|
||||
(interactive)
|
||||
(when (and (memq major-mode cosmo-format-modes)
|
||||
(member (file-name-extension (buffer-file-name))
|
||||
cosmo-format-exts)
|
||||
(not (member (file-name-nondirectory (buffer-name))
|
||||
cosmo-format-blacklist)))
|
||||
(let ((bin (cosmo--find-clang-format-bin)))
|
||||
(when bin
|
||||
(let ((p (point))
|
||||
(tmp (make-temp-file "cosmo-format"))
|
||||
(arg (or cosmo-format-arg
|
||||
(and (locate-dominating-file
|
||||
(buffer-file-name)
|
||||
".clang-format")
|
||||
"-style=file"))))
|
||||
(when arg
|
||||
(write-region nil nil tmp)
|
||||
(let ((buf (get-buffer-create "*clang-format*"))
|
||||
(exe (cosmo--find-clang-format-bin)))
|
||||
;; (with-current-buffer buf
|
||||
;; (set-process-sentinel
|
||||
;; (call-process exe tmp t nil arg)
|
||||
;; (lambda (_ _)
|
||||
;; (display-buffer buf))))
|
||||
(with-current-buffer buf
|
||||
(call-process exe tmp t nil arg))
|
||||
(replace-buffer-contents buf)
|
||||
(kill-buffer buf)
|
||||
(delete-file tmp nil))))))))
|
||||
|
||||
(add-hook 'before-save-hook 'cosmo-format)
|
||||
|
||||
(provide 'cosmo-format)
|
||||
|
||||
;;; cosmo-format.el ends here
|
764
tool/emacs/cosmo-stuff.el
Normal file
764
tool/emacs/cosmo-stuff.el
Normal file
|
@ -0,0 +1,764 @@
|
|||
;; ╔──────────────────────────────────────────────────────────────────╗
|
||||
;; │ To the extent possible under law, Justine Tunney has waived │
|
||||
;; │ all copyright and related or neighboring rights to this file, │
|
||||
;; │ as it is written in the following disclaimers: │
|
||||
;; │ • http://unlicense.org/ │
|
||||
;; │ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
;; ╚──────────────────────────────────────────────────────────────────╝
|
||||
;; Hodgepodge of copypasta from Justine's Emacs config intended to be
|
||||
;; helpful to those wanting to configure their own Emacs editor to work
|
||||
;; pretty well as a Cosmopolitan IDE.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'asm-mode)
|
||||
(require 'cc-mode)
|
||||
(require 'fortran)
|
||||
(require 'cosmo-c-builtins)
|
||||
(require 'cosmo-c-constants)
|
||||
(require 'cosmo-c-keywords)
|
||||
(require 'cosmo-c-types)
|
||||
(require 'dired)
|
||||
(require 'javadown)
|
||||
(require 'ld-script)
|
||||
(require 'make-mode)
|
||||
|
||||
(setq c-doc-comment-style 'javadown)
|
||||
|
||||
(add-to-list 'auto-mode-alist '("\\.x$" . c-mode)) ;; -aux-info
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Support Macros
|
||||
|
||||
(defmacro setql (var val)
|
||||
`(set (make-local-variable ',var) ,val))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Support Functions
|
||||
|
||||
(defun cosmo-contains (x s &optional icase)
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(let ((case-fold-search icase))
|
||||
(not (null (string-match-p (regexp-quote x) s)))))
|
||||
|
||||
(defun cosmo-startswith (x s &optional icase)
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(not (null (string-prefix-p x s icase))))
|
||||
|
||||
(defun cosmo-endswith (x s &optional icase)
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(let ((p (- (length s) (length x))))
|
||||
(and (>= p 0)
|
||||
(eq t (compare-strings x nil nil
|
||||
s p nil icase)))))
|
||||
|
||||
(defun cosmo-replace (x y s)
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(let ((case-fold-search nil))
|
||||
(replace-regexp-in-string (regexp-quote x) y s t t)))
|
||||
|
||||
(defun cosmo-join (s l)
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(mapconcat 'identity l s))
|
||||
|
||||
(defun cosmo-lchop (p s)
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(if (and (>= (length s) (length p))
|
||||
(string= p (substring s 0 (length p))))
|
||||
(substring s (length p))
|
||||
s))
|
||||
|
||||
(defun cosmo-first-that (predicate list)
|
||||
(declare (pure t))
|
||||
(when list
|
||||
(if (funcall predicate (car list))
|
||||
(car list)
|
||||
(cosmo-first-that predicate (cdr list)))))
|
||||
|
||||
(defun cosmo-file-name-sans-extensions (filename)
|
||||
(save-match-data
|
||||
(let (directory
|
||||
(file (file-name-sans-versions
|
||||
(file-name-nondirectory filename))))
|
||||
(if (and (string-match "[.-].*\\'" file)
|
||||
(not (eq 0 (match-beginning 0))))
|
||||
(if (setq directory (file-name-directory filename))
|
||||
(concat directory (substring file 0 (match-beginning 0)))
|
||||
(substring file 0 (match-beginning 0)))
|
||||
filename))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; C-c . Jump to symbol definition
|
||||
;; C-c , Jump back to where we were
|
||||
;; C-c C-i Show references to symbol
|
||||
|
||||
;; TODO(jart): Why doesnt the default-directory variable work?
|
||||
(defun project-current (&optional maybe-prompt dir)
|
||||
(expand-file-name
|
||||
(file-name-directory
|
||||
(locate-dominating-file
|
||||
(buffer-name) "Makefile"))))
|
||||
|
||||
(defun cosmo-xref-find-references ()
|
||||
(interactive)
|
||||
(let ((case-fold-search nil))
|
||||
(xref-find-references (format "%S" (symbol-at-point)))))
|
||||
|
||||
(defun cosmo-xref-find-definitions ()
|
||||
(interactive)
|
||||
(let ((case-fold-search nil))
|
||||
(xref-find-definitions (format "%S" (symbol-at-point)))))
|
||||
|
||||
(global-set-key (kbd "M-,") 'xref-pop-marker-stack)
|
||||
(global-set-key (kbd "M-.") 'cosmo-xref-find-definitions)
|
||||
(global-set-key (kbd "C-c TAB") 'cosmo-xref-find-references)
|
||||
|
||||
(defun stop-asking-questions-etags ()
|
||||
(set (make-local-variable 'tags-file-name)
|
||||
(format "%s/TAGS"
|
||||
(or (locate-dominating-file (buffer-name) "Makefile")
|
||||
(file-name-directory (buffer-name))))))
|
||||
(add-hook 'c-mode-common-hook 'stop-asking-questions-etags)
|
||||
(setq tags-revert-without-query t)
|
||||
(setq kill-buffer-query-functions ;; disable kill buffer w/ process question
|
||||
(delq 'process-kill-buffer-query-function kill-buffer-query-functions))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Compile buffer and run associated test and/or display assembly
|
||||
;; C-c C-c Compile
|
||||
;; M-1 C-c C-c Compile w/ MODE=tiny
|
||||
;; M-2 C-c C-c Compile w/ MODE=opt
|
||||
;; M-3 C-c C-c Compile w/ MODE=rel
|
||||
;; M-4 C-c C-c Compile w/ MODE=dbg
|
||||
;; M-5 C-c C-c Compile w/ MODE=""
|
||||
|
||||
(defun cosmo-intest (&optional file-name)
|
||||
(let (path root pkg)
|
||||
(and (setq path (or (buffer-file-name) dired-directory))
|
||||
(setq root (locate-dominating-file path "Makefile"))
|
||||
(setq pkg (file-relative-name path root))
|
||||
(cosmo-startswith "test/" pkg))))
|
||||
|
||||
(defun cosmo--make-mode (arg &optional default)
|
||||
(cond ((eq arg 1) "tiny")
|
||||
((eq arg 2) "opt")
|
||||
((eq arg 3) "rel")
|
||||
((eq arg 4) "dbg")
|
||||
((eq arg 5) "")
|
||||
(default default)
|
||||
((cosmo-intest) "dbg")
|
||||
(t "")))
|
||||
|
||||
(defun cosmo--compile-command (this root kind mode)
|
||||
(let* ((ext (file-name-extension this)) ;; e.g. "c"
|
||||
(dir (file-name-directory this)) ;; e.g. "/home/jart/daisy/libc/"
|
||||
(dots (file-relative-name root dir)) ;; e.g. "../"
|
||||
(file (file-relative-name this root)) ;; e.g. "libc/crc32c.c"
|
||||
(name (file-name-sans-extension file)) ;; e.g. "libc/crc32c"
|
||||
(buddy (format "test/%s_test.c" name))
|
||||
(runs (format "o/$m/%s.com.runs TESTARGS=-b" name))
|
||||
(buns (format "o/$m/test/%s_test.com.runs TESTARGS=-b" name)))
|
||||
(cond ((not (member ext '("c" "cc" "s" "S" "rl" "f")))
|
||||
(format "m=%s; make -j8 -O MODE=$m SILENT=0 o/$m/%s"
|
||||
mode
|
||||
(directory-file-name
|
||||
(file-name-directory
|
||||
(file-relative-name this root)))))
|
||||
((cosmo-contains "_test." (buffer-file-name))
|
||||
(format "m=%s; make -j8 -O MODE=$m %s"
|
||||
mode runs))
|
||||
((file-exists-p (format "%s" buddy))
|
||||
(format (cosmo-join
|
||||
" && "
|
||||
'("m=%s; make -j8 -O o/$m/%s.o MODE=$m SILENT=0"
|
||||
"objdump -wzCd o/$m/%s.o"
|
||||
"make -j8 -O MODE=$m %s"))
|
||||
mode name name buns))
|
||||
((eq kind 'run)
|
||||
(format
|
||||
(cosmo-join
|
||||
" && "
|
||||
`("m=%s; f=o/$m/%s.com"
|
||||
,(concat "make -j8 -O $f MODE=$m SILENT=0")
|
||||
"./$f"))
|
||||
mode name))
|
||||
((and (file-regular-p this)
|
||||
(file-executable-p this))
|
||||
(format "./%s" file))
|
||||
('t
|
||||
(format
|
||||
(cosmo-join
|
||||
" && "
|
||||
`("m=%s; f=o/$m/%s.o"
|
||||
,(concat "make -j8 -O $f MODE=$m SILENT=0")
|
||||
"objdump -wzCd $f"))
|
||||
mode name)))))
|
||||
|
||||
(defun cosmo-compile (arg)
|
||||
(interactive "P")
|
||||
(let* ((this (or (buffer-file-name) dired-directory))
|
||||
(root (locate-dominating-file this "Makefile")))
|
||||
(when root
|
||||
(let* ((mode (cosmo--make-mode arg))
|
||||
(default-directory root)
|
||||
(compile-command (cosmo--compile-command this root nil mode)))
|
||||
(compile compile-command)))))
|
||||
|
||||
(defun cosmo-compile-hook ()
|
||||
(local-set-key (kbd "C-c C-c") 'cosmo-compile))
|
||||
|
||||
(progn
|
||||
(add-hook 'makefile-mode-hook 'cosmo-compile-hook)
|
||||
(add-hook 'asm-mode-hook 'cosmo-compile-hook)
|
||||
(add-hook 'ld-script-mode-hook 'cosmo-compile-hook)
|
||||
(add-hook 'dired-mode-hook 'cosmo-compile-hook)
|
||||
(add-hook 'c-mode-common-hook 'cosmo-compile-hook)
|
||||
(add-hook 'fortran-mode-hook 'cosmo-compile-hook)
|
||||
(add-hook 'protobuf-mode-hook 'cosmo-compile-hook))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Display assembly for C/C++ buffer
|
||||
;;
|
||||
;; C-c C-a Compile and show assembly, with a native optimized build
|
||||
;; C-c C-b Compile and show assembly, with a balanced build
|
||||
;;
|
||||
;; The ALT key may be used to override the default mode.
|
||||
;;
|
||||
;; M-1 C-c C-a Compile w/ MODE=tiny
|
||||
;; M-2 C-c C-a Compile w/ MODE=opt
|
||||
;; M-3 C-c C-a Compile w/ MODE=rel
|
||||
;; M-4 C-c C-a Compile w/ MODE=dbg
|
||||
;; M-5 C-c C-a Compile w/ MODE=""
|
||||
;;
|
||||
|
||||
(defvar cosmo--assembly-root nil)
|
||||
(defvar cosmo--assembly-pending nil)
|
||||
|
||||
(defun cosmo--scrub (regex replace)
|
||||
(replace-regexp regex replace nil (point-min) (point-max)))
|
||||
|
||||
(defun cosmo--fixup-asm ()
|
||||
(cosmo--scrub
|
||||
;; Code like this
|
||||
;;
|
||||
;; .section "GNU!GNU!GNU!.must.be.in.every.asm.or.mprotect.breaks"
|
||||
;;
|
||||
;; Isn't needed since the underlying issue is addressed by ape/ape.S
|
||||
;; which generates executable structure.
|
||||
" .section .note.GNU-stack,.*,@progbits\n"
|
||||
"")
|
||||
(cosmo--scrub
|
||||
;; Code like this
|
||||
;;
|
||||
;; and $2047, %edx
|
||||
;;
|
||||
;; Should be this
|
||||
;;
|
||||
;; and $2047,%edx
|
||||
;;
|
||||
;; Per our favored coding style.
|
||||
", "
|
||||
",")
|
||||
(cosmo--scrub
|
||||
;; Code like this
|
||||
;;
|
||||
;; .ascii "foo"
|
||||
;; .zero 1
|
||||
;;
|
||||
;; Should be this
|
||||
;;
|
||||
;; .ascii "foo"
|
||||
;; .zero 1
|
||||
;;
|
||||
;; @see -frecord-gcc-switches
|
||||
"\t\\.ascii\t\"\\([^\"]*\\)\"\n\t\\.zero\t1\n"
|
||||
"\t.asciz\t\"\\1\"\n")
|
||||
(cosmo--scrub
|
||||
;; Code like this
|
||||
;;
|
||||
;; movl %eax,a
|
||||
;; movb b,%bl
|
||||
;; movb $1,c
|
||||
;; incb d
|
||||
;; movq %xmm0,%rax
|
||||
;;
|
||||
;; Should be this
|
||||
;;
|
||||
;; mov %eax,a
|
||||
;; mov %bl,b
|
||||
;; movb $1,c
|
||||
;; incb d
|
||||
;; movq %xmm0,%rax # ;_;
|
||||
;;
|
||||
;; Because we dislike redundancy and don't want the
|
||||
;; ibmicroborlandtel crowd feeling too uncomfortable.
|
||||
(let ((names-a-register
|
||||
"%[A-Za-z]")
|
||||
(normal-arithmetic-ops
|
||||
(regexp-opt
|
||||
(list
|
||||
"rcr" "rcl" "ror" "rol" "hlt" "cmc" "div" "sar"
|
||||
"mov" "shl" "shr" "lea" "cmp" "adc" "sbb" "inc"
|
||||
"sub" "xor" "add" "and" "or" "not" "btc" "dec"
|
||||
"mul" "neg" "bt" "bsf" "bsr" "int" "test")))
|
||||
(prefixes
|
||||
(regexp-opt
|
||||
(list
|
||||
"es" "cs" "ss" "ds" "lock"
|
||||
"rep" "repnz" "repne" "repz" "repe"
|
||||
"rex.b" "rex.x" "rex.xb" "rex.r" "rex.rb" "rex.rx"
|
||||
"rex.rxb" "rex.w" "rex.wb" "rex.wx" "rex.wxb" "rex.wr"
|
||||
"rex.trb" "rex.wrx" "rex.wrxb"))))
|
||||
(concat "\\("
|
||||
"^[ \t]*"
|
||||
"\\(?:" prefixes " \\|\\)"
|
||||
normal-arithmetic-ops
|
||||
"\\)"
|
||||
"[bwlq]"
|
||||
"\\("
|
||||
"[ \t]+"
|
||||
"\\(?:"
|
||||
"%[A-Wa-w][^\n]+"
|
||||
"\\|"
|
||||
"[^%][^\n,]*,%[A-Za-z][^\n]+"
|
||||
"\\)"
|
||||
"\\)"))
|
||||
"\\1\\2")
|
||||
;; Scroll first function to top of display.
|
||||
(goto-char (point-min))
|
||||
(when (search-forward-regexp
|
||||
"\t\\.type[^\n]*@function" nil t)
|
||||
(recenter-top-bottom 'top)))
|
||||
|
||||
(defun cosmo--assembly-compilation-finished (compilebuf msg)
|
||||
(when cosmo--assembly-pending
|
||||
(let ((asm-gcc (car cosmo--assembly-pending))
|
||||
(asm-clang (cdr cosmo--assembly-pending))
|
||||
width
|
||||
asm-gcc-buffer
|
||||
asm-gcc-window
|
||||
asm-clang-buffer
|
||||
asm-clang-window)
|
||||
(setq cosmo--assembly-pending nil)
|
||||
(when (not (cosmo-contains "finished" msg))
|
||||
(error "making assembly failed: %s" msg))
|
||||
(let ((f (format "%s/%s" cosmo--assembly-root asm-gcc)))
|
||||
(when (or (null asm-gcc) (not (file-exists-p f)))
|
||||
(error "asm-gcc not found: %s" f)))
|
||||
(let ((f (format "%s/%s" cosmo--assembly-root asm-clang)))
|
||||
(when (or (null asm-gcc) (not (file-exists-p f)))
|
||||
(error "asm-gcc not found: %s" f)))
|
||||
(delete-other-windows)
|
||||
(setq width (window-total-width))
|
||||
(setq asm-gcc-buffer (find-file-noselect asm-gcc t nil nil))
|
||||
(setq asm-clang-buffer (find-file-noselect asm-clang t nil nil))
|
||||
(setq asm-clang-window (split-window-right (- width (/ width 4))))
|
||||
(setq asm-gcc-window (split-window-right (- (- width (/ width 4)) (/ width 4))))
|
||||
(set-window-buffer asm-gcc-window asm-gcc-buffer)
|
||||
(set-window-buffer asm-clang-window asm-clang-buffer)
|
||||
(other-window 1)
|
||||
(cosmo--fixup-asm)
|
||||
(save-buffer)
|
||||
(bury-buffer (current-buffer))
|
||||
(other-window 1)
|
||||
(cosmo--fixup-asm)
|
||||
(save-buffer)
|
||||
(bury-buffer (current-buffer))
|
||||
(other-window 1)
|
||||
(bury-buffer compilebuf))))
|
||||
|
||||
(defun cosmo--purge-file (path)
|
||||
(let ((b (find-file-noselect path t nil nil)))
|
||||
(when b
|
||||
(with-current-buffer b
|
||||
(save-buffer))
|
||||
(when (not (kill-buffer b))
|
||||
(error "couldn't kill asm buffer"))))
|
||||
(delete-file path t))
|
||||
|
||||
(defun cosmo--assembly (arg extra-make-flags)
|
||||
(let* ((this (expand-file-name (or (buffer-file-name) dired-directory)))
|
||||
(root (expand-file-name (locate-dominating-file this "Makefile"))))
|
||||
(when root
|
||||
(let* ((mode (cosmo--make-mode arg "opt"))
|
||||
(ext (file-name-extension this))
|
||||
(dir (file-name-directory this))
|
||||
(dots (file-relative-name root dir))
|
||||
(file (file-relative-name this root))
|
||||
(name (file-name-sans-extension file))
|
||||
(asm-gcc (format "o/%s/%s-gcc.asm" mode name))
|
||||
(asm-clang (format "o/%s/%s-clang.asm" mode name)))
|
||||
(when (not (member ext '("c" "cc" "f")))
|
||||
(error "don't know how to show assembly for non c/c++ source file"))
|
||||
(let* ((default-directory root)
|
||||
(compile-command
|
||||
(format "make %s SILENT=0 -j8 -O MODE=%s %s %s"
|
||||
(or extra-make-flags "") mode asm-gcc asm-clang)))
|
||||
(save-buffer)
|
||||
(set-visited-file-modtime (current-time))
|
||||
(cosmo--purge-file asm-gcc)
|
||||
(cosmo--purge-file asm-clang)
|
||||
(save-buffer)
|
||||
(setq cosmo--assembly-root root)
|
||||
(setq cosmo--assembly-pending (cons asm-gcc asm-clang))
|
||||
(let ((errormsg (shell-command-to-string (format "touch %s" file))))
|
||||
(when (not (equal "" errormsg))
|
||||
(error errormsg)))
|
||||
(revert-buffer :ignore-auto :noconfirm)
|
||||
(compile compile-command))))))
|
||||
|
||||
(defun cosmo-assembly (arg)
|
||||
(interactive "P")
|
||||
(setq arg (or arg 2))
|
||||
(cond ((not (eq 0 (logand 8 arg)))
|
||||
(cosmo--assembly (setq arg (logand (lognot 8)))
|
||||
"SILENT=0 COPTS='-ffast-math -O3 -funsafe-math-optimizations -fsched2-use-superblocks'"))
|
||||
(t (cosmo--assembly arg "SILENT=0 COPTS='-O3'"))))
|
||||
|
||||
(defun cosmo-assembly-native (arg)
|
||||
(interactive "P")
|
||||
(setq arg (or arg 3))
|
||||
(cond ((not (eq 0 (logand 8 arg)))
|
||||
(cosmo--assembly
|
||||
(setq arg (logand (lognot 8)))
|
||||
"SILENT=0 CCFLAGS=--verbose COPTS='$(IEEE_MATH)' TARGET_ARCH='-march=znver2'"))
|
||||
(t
|
||||
(cosmo--assembly
|
||||
arg
|
||||
"SILENT=0 CCFLAGS=--verbose COPTS='$(MATHEMATICAL) -O3' TARGET_ARCH='-march=znver2'"))))
|
||||
|
||||
(defun cosmo-assembly-icelake (arg)
|
||||
(interactive "P")
|
||||
(setq arg (or arg 3))
|
||||
(cond ((not (eq 0 (logand 8 arg)))
|
||||
(cosmo--assembly
|
||||
(setq arg (logand (lognot 8)))
|
||||
"SILENT=0 CCFLAGS=--verbose COPTS='$(MATHEMATICAL) -O3' TARGET_ARCH='-march=icelake-client'"))
|
||||
(t
|
||||
(cosmo--assembly
|
||||
arg
|
||||
"SILENT=0 CCFLAGS=--verbose COPTS='$(MATHEMATICAL) -O3' TARGET_ARCH='-march=icelake-client'"))))
|
||||
|
||||
(defun cosmo-assembly-balanced (arg)
|
||||
(interactive "P")
|
||||
(cosmo--assembly (or arg 5) "CFLAGS='-O2 -ftrapv' SILENT=0"))
|
||||
|
||||
(defun cosmo-mca (arg)
|
||||
(interactive "P")
|
||||
(let (code
|
||||
delete
|
||||
cleanup
|
||||
(inhibit-message t)
|
||||
(inhibit-read-only t)
|
||||
(term (getenv "TERM"))
|
||||
(prog (executable-find "llvm-mca-10"))
|
||||
(buf1 (get-buffer-create "*mca*"))
|
||||
(buf2 (generate-new-buffer "*mca*")))
|
||||
(setenv "TERM" "xterm-256color")
|
||||
(setq cleanup
|
||||
(lambda ()
|
||||
(setenv term)
|
||||
(kill-buffer buf2)
|
||||
(when delete (delete-file delete))))
|
||||
(condition-case exc
|
||||
(progn
|
||||
(if (not (buffer-modified-p))
|
||||
(setq code (buffer-file-name))
|
||||
(setq code (make-temp-file "mca.s"))
|
||||
(write-region nil nil code)
|
||||
(setq delete code))
|
||||
(with-current-buffer buf2
|
||||
(insert "\n")
|
||||
(setq rc (call-process prog nil t nil
|
||||
"-mcpu=skylake"
|
||||
"-mtriple=x86_64-pc-linux-gnu"
|
||||
"--bottleneck-analysis"
|
||||
"-instruction-info"
|
||||
"-iterations=8"
|
||||
"-all-stats"
|
||||
"-all-views"
|
||||
"-timeline"
|
||||
code)))
|
||||
(with-current-buffer buf1
|
||||
(replace-buffer-contents buf2)
|
||||
(if (eq rc 0)
|
||||
(fundamental-mode)
|
||||
(compilation-mode))
|
||||
(xterm-color-colorize-buffer)
|
||||
(display-buffer (current-buffer))))
|
||||
('error
|
||||
(funcall cleanup)
|
||||
(error exc)))
|
||||
(funcall cleanup)))
|
||||
|
||||
(defun cosmo-assemble-hook ()
|
||||
(add-to-list 'compilation-finish-functions
|
||||
'cosmo--assembly-compilation-finished)
|
||||
(local-set-key (kbd "C-c C-a") 'cosmo-assembly)
|
||||
(local-set-key (kbd "C-c C-b") 'cosmo-assembly-balanced)
|
||||
(local-set-key (kbd "C-c C-n") 'cosmo-assembly-native)
|
||||
(local-set-key (kbd "C-c C-i") 'cosmo-assembly-icelake))
|
||||
|
||||
(defun cosmo-mca-hook ()
|
||||
;; (local-set-key (kbd "C-c C-h") 'cosmo-mca)
|
||||
)
|
||||
|
||||
(progn
|
||||
(add-hook 'asm-mode-hook 'cosmo-mca-hook)
|
||||
(add-hook 'makefile-mode-hook 'cosmo-assemble-hook)
|
||||
(add-hook 'asm-mode-hook 'cosmo-assemble-hook)
|
||||
(add-hook 'ld-script-mode-hook 'cosmo-assemble-hook)
|
||||
(add-hook 'dired-mode-hook 'cosmo-assemble-hook)
|
||||
(add-hook 'c-mode-common-hook 'cosmo-assemble-hook)
|
||||
(add-hook 'fortran-mode-hook 'cosmo-assemble-hook)
|
||||
(add-hook 'protobuf-mode-hook 'cosmo-assemble-hook))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Run buffer.
|
||||
;; C-c C-r Run
|
||||
;; M-1 C-c C-r Run w/ MODE=tiny
|
||||
;; M-2 C-c C-r Run w/ MODE=opt
|
||||
;; M-3 C-c C-r Run w/ MODE=rel
|
||||
;; M-4 C-c C-r Run w/ MODE=dbg
|
||||
;; M-5 C-c C-r Run w/ MODE=""
|
||||
|
||||
(defun cosmo-run (arg)
|
||||
(interactive "P")
|
||||
(let* ((this (or (buffer-file-name) dired-directory))
|
||||
(root (or (locate-dominating-file this "Makefile") default-directory))
|
||||
(file (file-relative-name this root)))
|
||||
(when root
|
||||
(let ((default-directory root))
|
||||
(save-buffer)
|
||||
(cond ((memq major-mode '(c-mode c++-mode asm-mode fortran-mode))
|
||||
(let* ((mode (cosmo--make-mode arg))
|
||||
(compile-command (cosmo--compile-command this root 'run mode)))
|
||||
(compile compile-command)))
|
||||
((eq major-mode 'sh-mode)
|
||||
(compile (format "sh %s" file)))
|
||||
((eq major-mode 'python-mode)
|
||||
(compile (format "python %s" file)))
|
||||
('t
|
||||
(error "cosmo-run: unknown major mode")))))))
|
||||
|
||||
(progn
|
||||
(define-key asm-mode-map (kbd "C-c C-r") 'cosmo-run)
|
||||
(define-key c-mode-base-map (kbd "C-c C-r") 'cosmo-run)
|
||||
(define-key fortran-mode-map (kbd "C-c C-r") 'cosmo-run)
|
||||
(define-key sh-mode-map (kbd "C-c C-r") 'cosmo-run)
|
||||
(define-key python-mode-map (kbd "C-c C-r") 'cosmo-run))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Debug buffer.
|
||||
;; C-c C-d Run in GDB/GUD
|
||||
;; M-1 C-c C-d Run in GDB/GUD w/ MODE=tiny
|
||||
;; M-2 C-c C-d Run in GDB/GUD w/ MODE=opt
|
||||
;; M-3 C-c C-d Run in GDB/GUD w/ MODE=rel
|
||||
;; M-4 C-c C-d Run in GDB/GUD w/ MODE=dbg
|
||||
;; M-5 C-c C-d Run in GDB/GUD w/ MODE=""
|
||||
|
||||
(defun cosmo-debug (arg)
|
||||
(interactive "P")
|
||||
(let* ((this (or (buffer-file-name) dired-directory))
|
||||
(root (locate-dominating-file this "Makefile")))
|
||||
(when root
|
||||
(let* ((mode (cosmo--make-mode arg "dbg"))
|
||||
(name (file-relative-name this root))
|
||||
(next (file-name-sans-extension name))
|
||||
(exec (format "o/%s/%s.com.dbg" mode next))
|
||||
(default-directory root)
|
||||
(compile-command (cosmo--compile-command this root nil mode)))
|
||||
(compile compile-command)
|
||||
(gdb (format "gdb -q -nh -i=mi %s -ex run" exec))))))
|
||||
|
||||
(progn
|
||||
(define-key asm-mode-map (kbd "C-c C-d") 'cosmo-debug)
|
||||
(define-key c-mode-base-map (kbd "C-c C-d") 'cosmo-debug))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; C-c C-t Toggle buffer between source file and unit test file.
|
||||
|
||||
(defun cosmo-toggle-buddy ()
|
||||
(interactive)
|
||||
(let* ((this (or (buffer-file-name) dired-directory))
|
||||
(root (locate-dominating-file this "Makefile")))
|
||||
(when root
|
||||
(let* ((name (file-relative-name this root))
|
||||
(dir (file-name-directory this))
|
||||
(pkgname (file-name-nondirectory (substring dir 0 -1)))
|
||||
(dots (file-relative-name root dir))
|
||||
(notest (cosmo-file-name-sans-extensions
|
||||
(cosmo-replace "_test" "" (cosmo-lchop "test/" name))))
|
||||
(buddy
|
||||
(cond ((and (cosmo-startswith "test/" dir)
|
||||
(cosmo-endswith "/test.mk" name))
|
||||
(message (format "%s/%s.mk" (substring dir 5) pkgname))
|
||||
(format "%s/%s.mk" (substring dir 5) pkgname))
|
||||
((cosmo-startswith "test/" name)
|
||||
(cosmo-first-that
|
||||
'file-exists-p
|
||||
(list (concat dots notest ".s")
|
||||
(concat dots notest ".S")
|
||||
(concat dots notest ".f")
|
||||
(concat dots notest ".F")
|
||||
(concat dots notest ".c")
|
||||
(concat dots notest ".cc")
|
||||
(concat dots notest ".rl")
|
||||
(concat dots notest ".ncabi.c")
|
||||
(concat dots notest ".hookabi.c")
|
||||
(concat dots notest ".h"))))
|
||||
(t
|
||||
(format "%stest/%s_test.c"
|
||||
dots (cosmo-file-name-sans-extensions name))))))
|
||||
(when buddy
|
||||
(find-file buddy))))))
|
||||
|
||||
(progn
|
||||
(global-set-key (kbd "C-c C-t") 'cosmo-toggle-buddy))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; C-c C-h Add Include Line
|
||||
|
||||
(defun cosmo-add-include ()
|
||||
(interactive)
|
||||
(let* ((no-whine t)
|
||||
(tag-file "HTAGS")
|
||||
(this (buffer-name))
|
||||
(case-fold-search nil)
|
||||
(search (thing-at-point 'symbol))
|
||||
(buffer (find-file-noselect (format "%s/%s"
|
||||
(locate-dominating-file
|
||||
this tag-file)
|
||||
tag-file)
|
||||
no-whine))
|
||||
(header (with-current-buffer buffer
|
||||
(revert-buffer :ignore-auto :noconfirm)
|
||||
(save-excursion
|
||||
(goto-char 0)
|
||||
(when (re-search-forward
|
||||
(concat "\177" search "\001") nil t)
|
||||
(when (re-search-backward "\f\n\\([^,]*\\)," nil t)
|
||||
(match-string 1))))))
|
||||
(root (locate-dominating-file this "Makefile"))
|
||||
(name (file-relative-name this root)))
|
||||
(when header
|
||||
(when (not (equal header name))
|
||||
(save-excursion
|
||||
(goto-char 0)
|
||||
(re-search-forward "#include" nil t)
|
||||
(re-search-forward "^$")
|
||||
(re-search-backward "#include" nil t)
|
||||
(beginning-of-line)
|
||||
(insert (concat "#include \"" header "\"\n"))))
|
||||
(message header))))
|
||||
|
||||
(progn
|
||||
(define-key asm-mode-map (kbd "C-c C-h") 'cosmo-add-include)
|
||||
(define-key c-mode-base-map (kbd "C-c C-h") 'cosmo-add-include))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; C-c C-o Show Optimization Report
|
||||
|
||||
(defun cosmo-show-optinfo (arg)
|
||||
(interactive "P")
|
||||
(let* ((mode (cosmo--make-mode arg "opt"))
|
||||
(this (or (buffer-file-name) dired-directory))
|
||||
(root (locate-dominating-file this "Makefile")))
|
||||
(when root
|
||||
(let* ((name (file-relative-name this root))
|
||||
(buddy
|
||||
(format "%s/o/%s/%s.optinfo.gz"
|
||||
root mode (cosmo-file-name-sans-extensions name))))
|
||||
(when buddy
|
||||
(find-file buddy))))))
|
||||
(defun cosmo-lisp-is-the-worst-this-is-so-tiring ()
|
||||
(define-key c-mode-base-map (kbd "C-c C-o") 'cosmo-show-optinfo))
|
||||
(add-hook 'c-mode-common-hook 'cosmo-lisp-is-the-worst-this-is-so-tiring)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Cosmopolitan Extended Language Keyword Definitions
|
||||
|
||||
(defun cosmo-keywords-hook ()
|
||||
(font-lock-add-keywords
|
||||
nil `((,cosmo-c-keywords-regex . font-lock-keyword-face)
|
||||
(,cosmo-c-builtins-regex . font-lock-builtin-face)
|
||||
(,cosmo-c-constants-regex . font-lock-constant-face)
|
||||
(,cosmo-c-types-regex . font-lock-type-face))))
|
||||
|
||||
(add-hook 'c-mode-common-hook 'cosmo-keywords-hook)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Symbol naming convention conversion
|
||||
|
||||
;; e.g. STARTF_USESHOWWINDOW -> kNtStartfUseshowwindow
|
||||
(defun cosmo--ms-to-google-const (s)
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(let ((d (downcase (substring s 1))))
|
||||
(cosmo-replace
|
||||
"kNtNt" "kNt"
|
||||
(concat
|
||||
"kNt"
|
||||
(substring s 0 1)
|
||||
(replace-regexp-in-string
|
||||
"_\\([A-Za-z]\\)"
|
||||
(lambda (m)
|
||||
(upcase (match-string 1 m)))
|
||||
d)))))
|
||||
|
||||
;; e.g. kNtStartfUseshowwindow -> STARTF_USESHOWWINDOW
|
||||
(defun cosmo--google-to-ms-const (s)
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(upcase (replace-regexp-in-string
|
||||
"\\(.\\)\\([A-Z]\\)"
|
||||
(lambda (m)
|
||||
(upcase (concat
|
||||
(match-string 1 m) "_"
|
||||
(match-string 2 m))))
|
||||
(substring s 3)
|
||||
t)))
|
||||
|
||||
(defun cosmo-toggle-ms-const ()
|
||||
(interactive)
|
||||
(let* ((case-fold-search nil)
|
||||
(bounds (if (use-region-p)
|
||||
(cons (region-beginning) (region-end))
|
||||
(bounds-of-thing-at-point 'symbol)))
|
||||
(text (buffer-substring-no-properties (car bounds) (cdr bounds))))
|
||||
(when bounds
|
||||
(let ((fn (if (or (cosmo-contains "_" text)
|
||||
(equal text (upcase text)))
|
||||
'cosmo--ms-to-google-const
|
||||
'cosmo--google-to-ms-const)))
|
||||
(delete-region (car bounds) (cdr bounds))
|
||||
(insert (funcall fn text))))))
|
||||
|
||||
;; (define-key c-mode-base-map (kbd "C-c C-l") 'cosmo-toggle-ms-const)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; CP/M EOF for the lulz
|
||||
|
||||
(defun cosmo-before-save ()
|
||||
(cond ((memq major-mode '(c-mode asm-mode))
|
||||
(set (make-local-variable 'require-final-newline)
|
||||
(not (equal (buffer-substring-no-properties
|
||||
(- (point-max) 1) (point-max))
|
||||
"\x1a"))))))
|
||||
|
||||
(add-hook 'before-save-hook 'cosmo-before-save)
|
||||
|
||||
(provide 'cosmo-stuff)
|
||||
|
||||
;;; cosmo-stuff.el ends here
|
53
tool/emacs/javadown.el
Normal file
53
tool/emacs/javadown.el
Normal file
|
@ -0,0 +1,53 @@
|
|||
;;; javadown.el --- C/C++ Markdown Javadocs
|
||||
|
||||
;; Copyright 2019 Justine Tunney
|
||||
|
||||
;; Author: Justine Tunney
|
||||
;; Version: 0.1
|
||||
|
||||
;; 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.
|
||||
;;
|
||||
;; 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.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Unintentionally empty.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cc-fonts)
|
||||
|
||||
(defconst javadown-font-lock-doc-comments
|
||||
`(;; e.g. ### Implementation Details
|
||||
("^\\(/\\*\\)?\\(\\s \\|\\*\\)*\\(#+[^\n\r]+\\)"
|
||||
3 ,c-doc-markup-face-name prepend nil)
|
||||
;; e.g. {@code param}
|
||||
("{@[a-z]+[^}\n\r]*}"
|
||||
0 ,c-doc-markup-face-name prepend nil)
|
||||
;; e.g. @param name does stuff
|
||||
("^\\(/\\*\\)?\\(\\s \\|\\*\\)*\\(@[a-z]+\\)"
|
||||
3 ,c-doc-markup-face-name prepend nil)
|
||||
;; e.g. <video src=doge.mp4>
|
||||
(,(concat "</?\\sw"
|
||||
"\\("
|
||||
(concat "\\sw\\|\\s \\|[=\n\r*.:]\\|"
|
||||
"\"[^\"]*\"\\|'[^']*'")
|
||||
"\\)*>")
|
||||
0 ,c-doc-markup-face-name prepend nil)))
|
||||
|
||||
(defconst javadown-font-lock-keywords
|
||||
`((,(lambda (limit)
|
||||
(c-font-lock-doc-comments "/\\*\\*" limit
|
||||
javadown-font-lock-doc-comments)))))
|
||||
|
||||
(provide 'javadown)
|
||||
|
||||
;;; javadown.el ends here
|
486
tool/emacs/key.py
Normal file
486
tool/emacs/key.py
Normal file
|
@ -0,0 +1,486 @@
|
|||
import os,sys,re
|
||||
|
||||
kar_types = frozenset([
|
||||
"char",
|
||||
"signed char",
|
||||
"unsigned char",
|
||||
"int",
|
||||
"signed",
|
||||
"signed int",
|
||||
"unsigned",
|
||||
"unsigned int",
|
||||
"short",
|
||||
"short int",
|
||||
"short signed",
|
||||
"short signed int",
|
||||
"short unsigned",
|
||||
"short unsigned int",
|
||||
"signed short",
|
||||
"signed short int",
|
||||
"unsigned short",
|
||||
"unsigned short int",
|
||||
"long",
|
||||
"long int",
|
||||
"long signed",
|
||||
"long signed int",
|
||||
"long unsigned",
|
||||
"long unsigned int",
|
||||
"signed long",
|
||||
"signed long int",
|
||||
"unsigned long",
|
||||
"unsigned long int",
|
||||
"float",
|
||||
"double",
|
||||
])
|
||||
|
||||
ansi_types = frozenset([
|
||||
"void",
|
||||
"wchar_t",
|
||||
"wint_t",
|
||||
"size_t",
|
||||
"long double",
|
||||
])
|
||||
|
||||
c99_types = frozenset([
|
||||
"long long",
|
||||
"long long int",
|
||||
"long long signed",
|
||||
"long long signed int",
|
||||
"long long unsigned",
|
||||
"long long unsigned int",
|
||||
"signed long long",
|
||||
"signed long long int",
|
||||
"unsigned long long",
|
||||
"unsigned long long int",
|
||||
"char16_t",
|
||||
"char32_t",
|
||||
"errno_t",
|
||||
"int8_t",
|
||||
"int16_t",
|
||||
"int32_t",
|
||||
"int64_t",
|
||||
"int_fast8_t",
|
||||
"int_fast16_t",
|
||||
"int_fast32_t",
|
||||
"int_fast64_t",
|
||||
"int_least16_t",
|
||||
"int_least32_t",
|
||||
"int_least64_t",
|
||||
"int_least8_t",
|
||||
"uint_fast16_t",
|
||||
"uint_fast32_t",
|
||||
"uint_fast64_t",
|
||||
"uint_fast8_t",
|
||||
"uint_least16_t",
|
||||
"uint_least32_t",
|
||||
"uint_least64_t",
|
||||
"uint_least8_t",
|
||||
"intmax_t",
|
||||
"intptr_t",
|
||||
"ptrdiff_t",
|
||||
"ssize_t",
|
||||
"uint16_t",
|
||||
"uint32_t",
|
||||
"uint64_t",
|
||||
"uint64_t",
|
||||
"uint8_t",
|
||||
"uintmax_t",
|
||||
"uintptr_t",
|
||||
])
|
||||
|
||||
c11_types = frozenset([
|
||||
"atomic_bool",
|
||||
"atomic_char",
|
||||
"atomic_schar",
|
||||
"atomic_uchar",
|
||||
"atomic_short",
|
||||
"atomic_ushort",
|
||||
"atomic_int",
|
||||
"atomic_uint",
|
||||
"atomic_long",
|
||||
"atomic_ulong",
|
||||
"atomic_llong",
|
||||
"atomic_ullong",
|
||||
"atomic_char16_t",
|
||||
"atomic_char32_t",
|
||||
"atomic_wchar_t",
|
||||
"atomic_int_least8_t",
|
||||
"atomic_uint_least8_t",
|
||||
"atomic_int_least16_t",
|
||||
"atomic_uint_least16_t",
|
||||
"atomic_int_least32_t",
|
||||
"atomic_uint_least32_t",
|
||||
"atomic_int_least64_t",
|
||||
"atomic_uint_least64_t",
|
||||
"atomic_int_fast8_t",
|
||||
"atomic_uint_fast8_t",
|
||||
"atomic_int_fast16_t",
|
||||
"atomic_uint_fast16_t",
|
||||
"atomic_int_fast32_t",
|
||||
"atomic_uint_fast32_t",
|
||||
"atomic_int_fast64_t",
|
||||
"atomic_uint_fast64_t",
|
||||
"atomic_intptr_t",
|
||||
"atomic_uintptr_t",
|
||||
"atomic_size_t",
|
||||
"atomic_ptrdiff_t",
|
||||
"atomic_intmax_t",
|
||||
"atomic_uintmax_t",
|
||||
])
|
||||
|
||||
gnu_types = frozenset([
|
||||
"__int128",
|
||||
"signed __int128",
|
||||
"unsigned __int128",
|
||||
])
|
||||
|
||||
cxx17_types = frozenset([
|
||||
"bool",
|
||||
])
|
||||
|
||||
cosmo_types = frozenset([
|
||||
"bool32",
|
||||
"int128_t",
|
||||
"int_fast128_t",
|
||||
"int_least128_t",
|
||||
"uint128_t",
|
||||
])
|
||||
|
||||
x86intrin_types = frozenset([
|
||||
"__m1",
|
||||
"__m2",
|
||||
"__m64",
|
||||
"__m128",
|
||||
"__m128_u",
|
||||
"__m128d",
|
||||
"__m128d_u",
|
||||
"__m128i",
|
||||
"__m128i_u",
|
||||
"__v16qi",
|
||||
"__v16qs",
|
||||
"__v16qu",
|
||||
"__v1di",
|
||||
"__v2df",
|
||||
"__v2di",
|
||||
"__v2du",
|
||||
"__v2sf",
|
||||
"__v2si",
|
||||
"__v4hi",
|
||||
"__v4sf",
|
||||
"__v4si",
|
||||
"__v4su",
|
||||
"__v8hi",
|
||||
"__v8hu",
|
||||
"__v8qi",
|
||||
])
|
||||
|
||||
################################################################################
|
||||
|
||||
kar_kws = frozenset([
|
||||
"auto",
|
||||
"if",
|
||||
"break",
|
||||
"case",
|
||||
"while",
|
||||
"continue",
|
||||
"default",
|
||||
"return",
|
||||
"do",
|
||||
"signed",
|
||||
"else",
|
||||
"sizeof",
|
||||
"extern",
|
||||
"struct",
|
||||
"switch",
|
||||
"for",
|
||||
"goto",
|
||||
"union",
|
||||
])
|
||||
|
||||
ansi_kws = frozenset([
|
||||
"auto",
|
||||
"if",
|
||||
"break",
|
||||
"case",
|
||||
"volatile",
|
||||
"while",
|
||||
"const",
|
||||
"register",
|
||||
"continue",
|
||||
"default",
|
||||
"return",
|
||||
"do",
|
||||
"double",
|
||||
"signed",
|
||||
"else",
|
||||
"sizeof",
|
||||
"static",
|
||||
"extern",
|
||||
"struct",
|
||||
"float",
|
||||
"switch",
|
||||
"for",
|
||||
"typedef",
|
||||
"goto",
|
||||
"union",
|
||||
"typedef",
|
||||
"enum",
|
||||
])
|
||||
|
||||
c99_kws= frozenset([
|
||||
"_Bool",
|
||||
"_Complex",
|
||||
"_Imaginary",
|
||||
"inline",
|
||||
"restrict",
|
||||
])
|
||||
|
||||
c11_kws = frozenset([
|
||||
"_Alignas",
|
||||
"_Alignof",
|
||||
"_Atomic",
|
||||
"_Generic",
|
||||
"_Noreturn",
|
||||
"_Static_assert",
|
||||
"_Thread_local",
|
||||
])
|
||||
|
||||
cxx17_kws = frozenset([
|
||||
"alignas",
|
||||
"alignof",
|
||||
"asm",
|
||||
"auto",
|
||||
"bool",
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"const_cast",
|
||||
"constexpr",
|
||||
"continue",
|
||||
"decltype",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"double",
|
||||
"dynamic_cast",
|
||||
"else",
|
||||
"enum",
|
||||
"explicit",
|
||||
"export",
|
||||
"extern",
|
||||
"false",
|
||||
"float",
|
||||
"for",
|
||||
"friend",
|
||||
"goto",
|
||||
"if",
|
||||
"inline",
|
||||
"mutable",
|
||||
"namespace",
|
||||
"new",
|
||||
"noexcept",
|
||||
"nullptr",
|
||||
"operator",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"register",
|
||||
"reinterpret_cast",
|
||||
"return",
|
||||
"short",
|
||||
"signed",
|
||||
"sizeof",
|
||||
"static",
|
||||
"static_assert",
|
||||
"static_cast",
|
||||
"struct",
|
||||
"switch",
|
||||
"template",
|
||||
"this",
|
||||
"thread_local",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typedef",
|
||||
"typeid",
|
||||
"typename",
|
||||
"union",
|
||||
"using",
|
||||
"virtual",
|
||||
"virtual",
|
||||
"volatile",
|
||||
"volatile",
|
||||
"while",
|
||||
])
|
||||
|
||||
cosmo_kws = frozenset([
|
||||
"pass",
|
||||
"alignas",
|
||||
"aligned",
|
||||
"alignof",
|
||||
"artificial",
|
||||
"attributeallocalign",
|
||||
"attributeallocsize",
|
||||
"autotype",
|
||||
"byanymeansnecessary",
|
||||
"compatfn",
|
||||
"decltype",
|
||||
"externinline",
|
||||
"firstclass",
|
||||
"flattenout",
|
||||
"forcealignargpointer",
|
||||
"forceinline",
|
||||
"frownedupon",
|
||||
"hasatleast",
|
||||
"hidden",
|
||||
"initarray",
|
||||
"interruptfn",
|
||||
"mallocesque",
|
||||
"mayalias",
|
||||
"memcpyesque",
|
||||
"nocallback",
|
||||
"nodebuginfo",
|
||||
"nodiscard",
|
||||
"noinline",
|
||||
"noinstrument",
|
||||
"nointerpose",
|
||||
"nooptimize",
|
||||
"noprune",
|
||||
"noreturn",
|
||||
"nosideeffect",
|
||||
"nothrow",
|
||||
"nothrow",
|
||||
"null",
|
||||
"nullterminated",
|
||||
"paramsnonnull",
|
||||
"preinitarray",
|
||||
"printfesque",
|
||||
"privileged",
|
||||
"pureconst",
|
||||
"reallocesque",
|
||||
"relegated",
|
||||
"returnsnonnull",
|
||||
"returnspointerwithnoaliases",
|
||||
"returnstwice",
|
||||
"scanfesque",
|
||||
"strftimeesque",
|
||||
"strlenesque",
|
||||
"testonly",
|
||||
"textexit",
|
||||
"textreal",
|
||||
"textstartup",
|
||||
"textwindows",
|
||||
"thatispacked",
|
||||
"threadlocal",
|
||||
"typeof",
|
||||
"unreachable",
|
||||
"warnifused",
|
||||
"winstruct",
|
||||
"nocallersavedregisters",
|
||||
"pass",
|
||||
"alignas",
|
||||
"aligned",
|
||||
"alignof",
|
||||
"artificial",
|
||||
"attributeallocalign",
|
||||
"attributeallocsize",
|
||||
"autotype",
|
||||
"byanymeansnecessary",
|
||||
"compatfn",
|
||||
"decltype",
|
||||
"externinline",
|
||||
"firstclass",
|
||||
"flattenout",
|
||||
"forcealignargpointer",
|
||||
"forceinline",
|
||||
"frownedupon",
|
||||
"hasatleast",
|
||||
"hidden",
|
||||
"initarray",
|
||||
"interruptfn",
|
||||
"mallocesque",
|
||||
"mayalias",
|
||||
"memcpyesque",
|
||||
"nocallback",
|
||||
"nodebuginfo",
|
||||
"nodiscard",
|
||||
"noinline",
|
||||
"noinstrument",
|
||||
"nointerpose",
|
||||
"nooptimize",
|
||||
"noprune",
|
||||
"noreturn",
|
||||
"nosideeffect",
|
||||
"nothrow",
|
||||
"nothrow",
|
||||
"null",
|
||||
"nullterminated",
|
||||
"paramsnonnull",
|
||||
"preinitarray",
|
||||
"printfesque",
|
||||
"privileged",
|
||||
"pureconst",
|
||||
"reallocesque",
|
||||
"relegated",
|
||||
"returnsnonnull",
|
||||
"returnspointerwithnoaliases",
|
||||
"returnstwice",
|
||||
"scanfesque",
|
||||
"strftimeesque",
|
||||
"strlenesque",
|
||||
"testonly",
|
||||
"textexit",
|
||||
"textreal",
|
||||
"textstartup",
|
||||
"textwindows",
|
||||
"thatispacked",
|
||||
"threadlocal",
|
||||
"typeof",
|
||||
"unreachable",
|
||||
"warnifused",
|
||||
"winstruct",
|
||||
"nocallersavedregisters",
|
||||
])
|
||||
|
||||
################################################################################
|
||||
|
||||
typegroups = (("kar", kar_types),
|
||||
("ansi", ansi_types),
|
||||
("c99", c99_types),
|
||||
("c11", c11_types),
|
||||
("gnu", gnu_types),
|
||||
("cxx17", cxx17_types),
|
||||
("cosmo", cosmo_types),
|
||||
("x86intrin", x86intrin_types))
|
||||
|
||||
kwgroups = (("kar", kar_kws),
|
||||
("ansi", ansi_kws),
|
||||
("c99", c99_kws),
|
||||
("c11", c11_kws),
|
||||
("cxx17", cxx17_kws),
|
||||
("cosmo", cosmo_kws))
|
||||
|
||||
types = reduce(lambda a,b: a|b[1], typegroups, set())
|
||||
kws = reduce(lambda a,b: a|b[1], kwgroups, set())
|
||||
|
||||
################################################################################
|
||||
|
||||
for name, gg, nonono in (("cosmo-c-types", typegroups, kws),
|
||||
("cosmo-c-keywords", kwgroups, types)):
|
||||
first = True
|
||||
sys.stdout.write("""\
|
||||
(defconst %s-regex
|
||||
(let (""" % name)
|
||||
for k, vs in gg:
|
||||
sys.stdout.write(("""%s(%s (list %s))
|
||||
""" % ("" if first else "\n ", k, """
|
||||
""".join('"%s"' % repr(s)[1:][:-1]
|
||||
for s in vs - nonono))).rstrip())
|
||||
first = False
|
||||
sys.stdout.write(""")
|
||||
(concat "\\<" (regexp-opt (append """)
|
||||
sys.stdout.write("""
|
||||
""".join(k for k,_ in gg))
|
||||
sys.stdout.write(""")) "\\>")))\n\n""")
|
185
tool/emacs/ld-script.el
Normal file
185
tool/emacs/ld-script.el
Normal file
|
@ -0,0 +1,185 @@
|
|||
;;; ld-script.el --- GNU linker script editing mode for Emacs
|
||||
|
||||
;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Masatake YAMATO<jet@gyve.org>
|
||||
;; Keywords: languages, faces
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Major mode for editing GNU linker (ld) scripts.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; Custom
|
||||
(defgroup ld-script nil
|
||||
"GNU linker script code editing commands for Emacs."
|
||||
:prefix "ld-script-"
|
||||
:group 'languages)
|
||||
|
||||
(defvar ld-script-location-counter-face 'ld-script-location-counter)
|
||||
(defface ld-script-location-counter
|
||||
'((t :weight bold :inherit font-lock-builtin-face))
|
||||
"Face for location counter in GNU ld script."
|
||||
:group 'ld-script)
|
||||
|
||||
;; Syntax rules
|
||||
(defvar ld-script-mode-syntax-table
|
||||
(let ((st (make-syntax-table)))
|
||||
(modify-syntax-entry ?\ "-" st)
|
||||
(modify-syntax-entry ?{ "(}" st)
|
||||
(modify-syntax-entry ?} "){" st)
|
||||
(modify-syntax-entry ?\( "()" st)
|
||||
(modify-syntax-entry ?\) ")(" st)
|
||||
(modify-syntax-entry ?\[ "(]" st)
|
||||
(modify-syntax-entry ?\] ")[" st)
|
||||
(modify-syntax-entry ?_ "_" st)
|
||||
(modify-syntax-entry ?. "_" st)
|
||||
(modify-syntax-entry ?\\ "\\" st)
|
||||
(modify-syntax-entry ?: "." st)
|
||||
(modify-syntax-entry ?, "." st)
|
||||
(modify-syntax-entry ?? "." st)
|
||||
(modify-syntax-entry ?= "." st)
|
||||
(modify-syntax-entry ?* ". 23" st)
|
||||
(modify-syntax-entry ?/ ". 14" st)
|
||||
(modify-syntax-entry ?+ "." st)
|
||||
(modify-syntax-entry ?- "." st)
|
||||
(modify-syntax-entry ?! "." st)
|
||||
(modify-syntax-entry ?~ "." st)
|
||||
(modify-syntax-entry ?% "." st)
|
||||
(modify-syntax-entry ?< "." st)
|
||||
(modify-syntax-entry ?> "." st)
|
||||
(modify-syntax-entry ?& "." st)
|
||||
(modify-syntax-entry ?| "." st)
|
||||
(modify-syntax-entry ?\" "\"" st)
|
||||
st)
|
||||
"Syntax table used while in `ld-script-mode'.")
|
||||
|
||||
;; Font lock keywords
|
||||
;; (The section number comes from ld's info.)
|
||||
(defvar ld-script-keywords
|
||||
'(
|
||||
;; 3.4.1 Setting the Entry Point
|
||||
"ENTRY"
|
||||
;; 3.4.2 Commands Dealing with Files
|
||||
"INCLUDE" "INPUT" "GROUP" "AS_NEEDED" "OUTPUT" "SEARCH_DIR" "STARTUP"
|
||||
;; 3.4.3 Commands Dealing with Object File Formats
|
||||
"OUTPUT_FORMAT" "TARGET"
|
||||
;; 3.4.4 Assign alias names to memory regions
|
||||
"REGION_ALIAS"
|
||||
;; 3.4.5 Other Linker Script Commands
|
||||
"ASSERT" "EXTERN" "FORCE_COMMON_ALLOCATION"
|
||||
"INHIBIT_COMMON_ALLOCATION" "INSERT" "AFTER" "BEFORE"
|
||||
"NOCROSSREFS" "NOCROSSREFS_TO" "OUTPUT_ARCH" "LD_FEATURE"
|
||||
;; 3.5.2 HIDDEN
|
||||
"HIDDEN"
|
||||
;; 3.5.3 PROVIDE
|
||||
"PROVIDE"
|
||||
;; 3.5.4 PROVIDE_HIDDEN
|
||||
"PROVIDE_HIDDEN"
|
||||
;; 3.6 SECTIONS Command
|
||||
"SECTIONS"
|
||||
;; 3.6.4.2 Input Section Wildcard Patterns
|
||||
"SORT" "SORT_NONE" "SORT_BY_NAME" "SORT_BY_ALIGNMENT"
|
||||
"SORT_BY_INIT_PRIORITY"
|
||||
;; 3.6.4.3 Input Section for Common Symbols
|
||||
"COMMON"
|
||||
;; 3.6.4.4 Input Section and Garbage Collection
|
||||
"KEEP"
|
||||
;; 3.6.5 Output Section Data
|
||||
"BYTE" "SHORT" "LONG" "QUAD" "SQUAD" "FILL"
|
||||
;; 3.6.6 Output Section Keywords
|
||||
"CREATE_OBJECT_SYMBOLS" "CONSTRUCTORS"
|
||||
"__CTOR_LIST__" "__CTOR_END__" "__DTOR_LIST__" "__DTOR_END__"
|
||||
;; 3.6.7 Output Section Discarding
|
||||
;; See `ld-script-font-lock-keywords'
|
||||
;; 3.6.8.1 Output Section Type
|
||||
"NOLOAD" "DSECT" "COPY" "INFO" "OVERLAY"
|
||||
;; 3.6.8.2 Output Section LMA
|
||||
"AT"
|
||||
;; 3.6.8.4 Forced Input Alignment
|
||||
"SUBALIGN"
|
||||
;; 3.6.8.5 Output Section Constraint
|
||||
"ONLY_IF_RO" "ONLY_IF_RW"
|
||||
;; 3.6.8.7 Output Section Phdr
|
||||
":PHDR"
|
||||
;; 3.7 MEMORY Command
|
||||
"MEMORY"
|
||||
;; 3.8 PHDRS Command
|
||||
"PHDRS" "FILEHDR" "FLAGS"
|
||||
"PT_NULL" "PT_LOAD" "PT_DYNAMIC" "PT_INTERP" "PT_NOTE" "PT_SHLIB" "PT_PHDR"
|
||||
"PT_GNU_STACK"
|
||||
;; 3.9 VERSION Command
|
||||
"VERSION")
|
||||
"Keywords used of GNU ld script.")
|
||||
|
||||
|
||||
;; 3.10.2 Symbolic Constants
|
||||
;; 3.10.9 Builtin Functions
|
||||
(defvar ld-script-builtins
|
||||
'("CONSTANT"
|
||||
"MAXPAGESIZE"
|
||||
"COMMONPAGESIZE"
|
||||
"ABSOLUTE"
|
||||
"ADDR"
|
||||
"ALIGN"
|
||||
"ALIGNOF"
|
||||
"BLOCK"
|
||||
"DATA_SEGMENT_ALIGN"
|
||||
"DATA_SEGMENT_END"
|
||||
"DATA_SEGMENT_RELRO_END"
|
||||
"DEFINED"
|
||||
"LENGTH" "len" "l"
|
||||
"LOADADDR"
|
||||
"LOG2CEIL"
|
||||
"MAX"
|
||||
"MIN"
|
||||
"NEXT"
|
||||
"ORIGIN" "org" "o"
|
||||
"SEGMENT_START"
|
||||
"SIZEOF"
|
||||
"SIZEOF_HEADERS"
|
||||
"sizeof_headers")
|
||||
"Builtin functions of GNU ld script.")
|
||||
|
||||
(defvar ld-script-font-lock-keywords
|
||||
(append
|
||||
`((,(concat "\\_<" (regexp-opt ld-script-keywords) "\\_>")
|
||||
0 font-lock-keyword-face)
|
||||
(,(concat "\\_<" (regexp-opt ld-script-builtins) "\\_>")
|
||||
0 font-lock-builtin-face)
|
||||
;; 3.6.7 Output Section Discarding
|
||||
;; 3.6.4.1 Input Section Basics
|
||||
;; 3.6.8.7 Output Section Phdr
|
||||
("/DISCARD/\\|EXCLUDE_FILE\\|:NONE" . font-lock-warning-face)
|
||||
("\\W\\(\\.\\)\\W" 1 ld-script-location-counter-face)
|
||||
)
|
||||
cpp-font-lock-keywords)
|
||||
"Default font-lock-keywords for `ld-script-mode'.")
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode ld-script-mode prog-mode "LD-Script"
|
||||
"A major mode to edit GNU ld script files"
|
||||
(set (make-local-variable 'comment-start) "/* ")
|
||||
(set (make-local-variable 'comment-end) " */")
|
||||
(set (make-local-variable 'font-lock-defaults)
|
||||
'(ld-script-font-lock-keywords nil)))
|
||||
|
||||
(provide 'ld-script)
|
||||
|
||||
;;; ld-script.el ends here
|
11
tool/emacs/optinfo-mode.el
Normal file
11
tool/emacs/optinfo-mode.el
Normal file
|
@ -0,0 +1,11 @@
|
|||
(require 'compile)
|
||||
|
||||
(define-derived-mode optinfo-mode compilation-mode "Optimization Info"
|
||||
(let ((root (locate-dominating-file (buffer-file-name) "Makefile")))
|
||||
(when root
|
||||
(setq-local default-directory root))))
|
||||
|
||||
(auto-compression-mode t)
|
||||
(add-to-list 'auto-mode-alist '("\\.optinfo\\(\\|\\.gz\\)$" . optinfo-mode))
|
||||
|
||||
(provide 'optinfo-mode)
|
224
tool/emacs/protobuf-mode.el
Normal file
224
tool/emacs/protobuf-mode.el
Normal file
|
@ -0,0 +1,224 @@
|
|||
;;; protobuf-mode.el --- major mode for editing protocol buffers.
|
||||
|
||||
;; Author: Alexandre Vassalotti <alexandre@peadrop.com>
|
||||
;; Created: 23-Apr-2009
|
||||
;; Version: 0.3
|
||||
;; Package-Version: 3.10.0
|
||||
;; Keywords: google protobuf languages
|
||||
|
||||
;; Redistribution and use in source and binary forms, with or without
|
||||
;; modification, are permitted provided that the following conditions are
|
||||
;; met:
|
||||
;;
|
||||
;; * Redistributions of source code must retain the above copyright
|
||||
;; notice, this list of conditions and the following disclaimer.
|
||||
;; * Redistributions in binary form must reproduce the above
|
||||
;; copyright notice, this list of conditions and the following disclaimer
|
||||
;; in the documentation and/or other materials provided with the
|
||||
;; distribution.
|
||||
;; * Neither the name of Google Inc. nor the names of its
|
||||
;; contributors may be used to endorse or promote products derived from
|
||||
;; this software without specific prior written permission.
|
||||
;;
|
||||
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Installation:
|
||||
;; - Put `protobuf-mode.el' in your Emacs load-path.
|
||||
;; - Add this line to your .emacs file:
|
||||
;; (require 'protobuf-mode)
|
||||
;;
|
||||
;; You can customize this mode just like any mode derived from CC Mode. If
|
||||
;; you want to add customizations specific to protobuf-mode, you can use the
|
||||
;; `protobuf-mode-hook'. For example, the following would make protocol-mode
|
||||
;; use 2-space indentation:
|
||||
;;
|
||||
;; (defconst my-protobuf-style
|
||||
;; '((c-basic-offset . 2)
|
||||
;; (indent-tabs-mode . nil)))
|
||||
;;
|
||||
;; (add-hook 'protobuf-mode-hook
|
||||
;; (lambda () (c-add-style "my-style" my-protobuf-style t)))
|
||||
;;
|
||||
;; Refer to the documentation of CC Mode for more information about
|
||||
;; customization details and how to use this mode.
|
||||
;;
|
||||
;; TODO:
|
||||
;; - Make highlighting for enum values work properly.
|
||||
;; - Fix the parser to recognize extensions as identifiers and not
|
||||
;; as casts.
|
||||
;; - Improve the parsing of option assignment lists. For example:
|
||||
;; optional int32 foo = 1 [(my_field_option) = 4.5];
|
||||
;; - Add support for fully-qualified identifiers (e.g., with a leading ".").
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cc-mode)
|
||||
|
||||
(eval-when-compile
|
||||
(and (= emacs-major-version 24)
|
||||
(>= emacs-minor-version 4)
|
||||
(require 'cl))
|
||||
(require 'cc-langs)
|
||||
(require 'cc-fonts))
|
||||
|
||||
;; This mode does not inherit properties from other modes. So, we do not use
|
||||
;; the usual `c-add-language' function.
|
||||
(eval-and-compile
|
||||
(put 'protobuf-mode 'c-mode-prefix "protobuf-"))
|
||||
|
||||
;; The following code uses of the `c-lang-defconst' macro define syntactic
|
||||
;; features of protocol buffer language. Refer to the documentation in the
|
||||
;; cc-langs.el file for information about the meaning of the -kwds variables.
|
||||
|
||||
(c-lang-defconst c-primitive-type-kwds
|
||||
protobuf '("double" "float" "int32" "int64" "uint32" "uint64" "sint32"
|
||||
"sint64" "fixed32" "fixed64" "sfixed32" "sfixed64" "bool"
|
||||
"string" "bytes" "group"))
|
||||
|
||||
(c-lang-defconst c-modifier-kwds
|
||||
protobuf '("required" "optional" "repeated"))
|
||||
|
||||
(c-lang-defconst c-class-decl-kwds
|
||||
protobuf '("message" "enum" "service"))
|
||||
|
||||
(c-lang-defconst c-constant-kwds
|
||||
protobuf '("true" "false"))
|
||||
|
||||
(c-lang-defconst c-other-decl-kwds
|
||||
protobuf '("package" "import"))
|
||||
|
||||
(c-lang-defconst c-other-kwds
|
||||
protobuf '("default" "max"))
|
||||
|
||||
(c-lang-defconst c-identifier-ops
|
||||
;; Handle extended identifiers like google.protobuf.MessageOptions
|
||||
protobuf '((left-assoc ".")))
|
||||
|
||||
;; The following keywords do not fit well in keyword classes defined by
|
||||
;; cc-mode. So, we approximate as best we can.
|
||||
|
||||
(c-lang-defconst c-type-list-kwds
|
||||
protobuf '("extensions" "to" "reserved"))
|
||||
|
||||
(c-lang-defconst c-typeless-decl-kwds
|
||||
protobuf '("extend" "rpc" "option" "returns"))
|
||||
|
||||
|
||||
;; Here we remove default syntax for loops, if-statements and other C
|
||||
;; syntactic features that are not supported by the protocol buffer language.
|
||||
|
||||
(c-lang-defconst c-brace-list-decl-kwds
|
||||
;; Remove syntax for C-style enumerations.
|
||||
protobuf nil)
|
||||
|
||||
(c-lang-defconst c-block-stmt-1-kwds
|
||||
;; Remove syntax for "do" and "else" keywords.
|
||||
protobuf nil)
|
||||
|
||||
(c-lang-defconst c-block-stmt-2-kwds
|
||||
;; Remove syntax for "for", "if", "switch" and "while" keywords.
|
||||
protobuf nil)
|
||||
|
||||
(c-lang-defconst c-simple-stmt-kwds
|
||||
;; Remove syntax for "break", "continue", "goto" and "return" keywords.
|
||||
protobuf nil)
|
||||
|
||||
(c-lang-defconst c-paren-stmt-kwds
|
||||
;; Remove special case for the "(;;)" in for-loops.
|
||||
protobuf nil)
|
||||
|
||||
(c-lang-defconst c-label-kwds
|
||||
;; Remove case label syntax for the "case" and "default" keywords.
|
||||
protobuf nil)
|
||||
|
||||
(c-lang-defconst c-before-label-kwds
|
||||
;; Remove special case for the label in a goto statement.
|
||||
protobuf nil)
|
||||
|
||||
(c-lang-defconst c-cpp-matchers
|
||||
;; Disable all the C preprocessor syntax.
|
||||
protobuf nil)
|
||||
|
||||
(c-lang-defconst c-decl-prefix-re
|
||||
;; Same as for C, except it does not match "(". This is needed for disabling
|
||||
;; the syntax for casts.
|
||||
protobuf "\\([\{\};,]+\\)")
|
||||
|
||||
|
||||
;; Add support for variable levels of syntax highlighting.
|
||||
|
||||
(defconst protobuf-font-lock-keywords-1 (c-lang-const c-matchers-1 protobuf)
|
||||
"Minimal highlighting for protobuf-mode.")
|
||||
|
||||
(defconst protobuf-font-lock-keywords-2 (c-lang-const c-matchers-2 protobuf)
|
||||
"Fast normal highlighting for protobuf-mode.")
|
||||
|
||||
(defconst protobuf-font-lock-keywords-3 (c-lang-const c-matchers-3 protobuf)
|
||||
"Accurate normal highlighting for protobuf-mode.")
|
||||
|
||||
(defvar protobuf-font-lock-keywords protobuf-font-lock-keywords-3
|
||||
"Default expressions to highlight in protobuf-mode.")
|
||||
|
||||
;; Our syntax table is auto-generated from the keyword classes we defined
|
||||
;; previously with the `c-lang-const' macro.
|
||||
(defvar protobuf-mode-syntax-table nil
|
||||
"Syntax table used in protobuf-mode buffers.")
|
||||
(or protobuf-mode-syntax-table
|
||||
(setq protobuf-mode-syntax-table
|
||||
(funcall (c-lang-const c-make-mode-syntax-table protobuf))))
|
||||
|
||||
(defvar protobuf-mode-abbrev-table nil
|
||||
"Abbreviation table used in protobuf-mode buffers.")
|
||||
|
||||
(defvar protobuf-mode-map nil
|
||||
"Keymap used in protobuf-mode buffers.")
|
||||
(or protobuf-mode-map
|
||||
(setq protobuf-mode-map (c-make-inherited-keymap)))
|
||||
|
||||
(easy-menu-define protobuf-menu protobuf-mode-map
|
||||
"Protocol Buffers Mode Commands"
|
||||
(cons "Protocol Buffers" (c-lang-const c-mode-menu protobuf)))
|
||||
|
||||
;;;###autoload (add-to-list 'auto-mode-alist '("\\.proto\\'" . protobuf-mode))
|
||||
|
||||
;;;###autoload
|
||||
(defun protobuf-mode ()
|
||||
"Major mode for editing Protocol Buffers description language.
|
||||
|
||||
The hook `c-mode-common-hook' is run with no argument at mode
|
||||
initialization, then `protobuf-mode-hook'.
|
||||
|
||||
Key bindings:
|
||||
\\{protobuf-mode-map}"
|
||||
(interactive)
|
||||
(kill-all-local-variables)
|
||||
(set-syntax-table protobuf-mode-syntax-table)
|
||||
(setq major-mode 'protobuf-mode
|
||||
mode-name "Protocol-Buffers"
|
||||
local-abbrev-table protobuf-mode-abbrev-table
|
||||
abbrev-mode t)
|
||||
(use-local-map protobuf-mode-map)
|
||||
(c-initialize-cc-mode t)
|
||||
(if (fboundp 'c-make-emacs-variables-local)
|
||||
(c-make-emacs-variables-local))
|
||||
(c-init-language-vars protobuf-mode)
|
||||
(c-common-init 'protobuf-mode)
|
||||
(easy-menu-add protobuf-menu)
|
||||
(c-run-mode-hooks 'c-mode-common-hook 'protobuf-mode-hook)
|
||||
(c-update-modeline))
|
||||
|
||||
(provide 'protobuf-mode)
|
||||
|
||||
;;; protobuf-mode.el ends here
|
50
tool/hash/crctab.c
Normal file
50
tool/hash/crctab.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* @fileoverview CRC Lookup Table Generator
|
||||
* @see http://reveng.sourceforge.net/crc-catalogue/17plus.htm
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s POLYNOMIAL\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
static uint32_t tab[256];
|
||||
crc32init(tab, strtoimax(argv[1], NULL, 0));
|
||||
for (unsigned i = 0; i < ARRAYLEN(tab); ++i) {
|
||||
if (i > 0) {
|
||||
printf(",");
|
||||
if (i % 6 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("0x%08x", tab[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
46
tool/hash/hash.mk
Normal file
46
tool/hash/hash.mk
Normal file
|
@ -0,0 +1,46 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_HASH
|
||||
|
||||
TOOL_HASH_SRCS := $(wildcard tool/hash/*.c)
|
||||
TOOL_HASH_COMS = $(TOOL_HASH_OBJS:%.o=%.com)
|
||||
|
||||
TOOL_HASH_OBJS = \
|
||||
$(TOOL_HASH_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(TOOL_HASH_SRCS:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_HASH_BINS = \
|
||||
$(TOOL_HASH_COMS) \
|
||||
$(TOOL_HASH_COMS:%=%.dbg)
|
||||
|
||||
TOOL_HASH_DIRECTDEPS = \
|
||||
LIBC_CONV \
|
||||
LIBC_FMT \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STUBS \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR
|
||||
|
||||
TOOL_HASH_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_HASH_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/tool/hash/hash.pkg: \
|
||||
$(TOOL_HASH_OBJS) \
|
||||
$(foreach x,$(TOOL_HASH_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/tool/hash/%.com.dbg: \
|
||||
$(TOOL_HASH_DEPS) \
|
||||
o/$(MODE)/tool/hash/%.o \
|
||||
o/$(MODE)/tool/hash/hash.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
$(TOOL_HASH_OBJS): \
|
||||
$(BUILD_FILES) \
|
||||
tool/hash/hash.mk
|
||||
|
||||
.PHONY: o/$(MODE)/tool/hash
|
||||
o/$(MODE)/tool/hash: $(TOOL_HASH_BINS) $(TOOL_HASH_CHECKS)
|
78
tool/net/dig.c
Normal file
78
tool/net/dig.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ai.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "tool/decode/lib/flagger.h"
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#include "tool/decode/lib/socknames.h"
|
||||
|
||||
void lookup(const char *name) {
|
||||
struct addrinfo hints = (struct addrinfo){.ai_family = AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
.ai_flags = AI_NUMERICSERV};
|
||||
struct addrinfo *addrs = NULL;
|
||||
if (getaddrinfo(name, "80", &hints, &addrs) == -1) {
|
||||
perror("getaddrinfo");
|
||||
exit(1);
|
||||
}
|
||||
if (addrs) {
|
||||
for (struct addrinfo *addr = addrs; addr; addr = addr->ai_next) {
|
||||
const unsigned char *ip =
|
||||
addr->ai_family == AF_INET
|
||||
? (const unsigned char *)&((struct sockaddr_in *)addr->ai_addr)
|
||||
->sin_addr
|
||||
: (const unsigned char *)"\0\0\0\0";
|
||||
printf("%s = %s\n", "ai_flags",
|
||||
recreateflags(kAddrInfoFlagNames, addr->ai_flags), addr->ai_flags);
|
||||
printf("%s = %s (%d)\n", "ai_family",
|
||||
findnamebyid(kAddressFamilyNames, addr->ai_family),
|
||||
addr->ai_family);
|
||||
printf("%s = %s (%d)\n", "ai_socktype",
|
||||
findnamebyid(kSockTypeNames, addr->ai_socktype),
|
||||
addr->ai_socktype);
|
||||
printf("%s = %s (%d)\n", "ai_protocol",
|
||||
findnamebyid(kProtocolNames, addr->ai_protocol),
|
||||
addr->ai_protocol);
|
||||
printf("%s = %d\n", "ai_addrlen", addr->ai_addrlen);
|
||||
printf("%s = %hhu.%hhu.%hhu.%hhu\n", "ai_addr", ip[0], ip[1], ip[2],
|
||||
ip[3]);
|
||||
printf("%s = %s\n", "ai_canonname", addr->ai_canonname);
|
||||
}
|
||||
freeaddrinfo(addrs);
|
||||
} else {
|
||||
fprintf(stderr, "%s: %s\n", name, "no results");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
lookup(argv[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
300
tool/net/echoserver.c
Normal file
300
tool/net/echoserver.c
Normal file
|
@ -0,0 +1,300 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/interruptiblecall.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/msg.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Asynchronous TCP/UDP Echo Server.
|
||||
*
|
||||
* make -j8 o/default/tool/net/echoserver.com
|
||||
* o/default/tool/net/echoserver.com udp:0.0.0.0:7 tcp:0.0.0.0:7
|
||||
*/
|
||||
|
||||
enum SocketKind {
|
||||
kSocketServer,
|
||||
kSocketClient,
|
||||
};
|
||||
|
||||
struct Message {
|
||||
struct iovec data;
|
||||
struct sockaddr_in dest;
|
||||
uint32_t destsize;
|
||||
};
|
||||
|
||||
struct Messages {
|
||||
size_t i, n;
|
||||
struct Message *p;
|
||||
};
|
||||
|
||||
struct Socket {
|
||||
int64_t fd;
|
||||
enum SocketKind kind;
|
||||
int type;
|
||||
int protocol;
|
||||
struct sockaddr_in addr;
|
||||
struct Messages egress; /* LIFO */
|
||||
};
|
||||
|
||||
struct Sockets {
|
||||
size_t i, n;
|
||||
struct Socket *p;
|
||||
};
|
||||
|
||||
struct Polls {
|
||||
size_t i, n;
|
||||
struct pollfd *p;
|
||||
};
|
||||
|
||||
struct Sockets g_sockets;
|
||||
struct Polls g_polls;
|
||||
|
||||
nodiscard char *DescribeAddress(struct sockaddr_in *addr) {
|
||||
char ip4buf[16];
|
||||
return xasprintf("%s:%hu",
|
||||
inet_ntop(addr->sin_family, &addr->sin_addr.s_addr, ip4buf,
|
||||
sizeof(ip4buf)),
|
||||
ntohs(addr->sin_port));
|
||||
}
|
||||
|
||||
nodiscard char *DescribeSocket(struct Socket *s) {
|
||||
return xasprintf("%s:%s", s->protocol == IPPROTO_UDP ? "udp" : "tcp",
|
||||
gc(DescribeAddress(&s->addr)));
|
||||
}
|
||||
|
||||
noreturn void ShowUsageAndExit(bool iserror) {
|
||||
FILE *f = iserror ? stderr : stdout;
|
||||
int rc = iserror ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
fprintf(f, "%s: %s %s\n", "Usage", g_argv[0], "PROTOCOL:ADDR:PORT...");
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetFlags(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "h")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
ShowUsageAndExit(false);
|
||||
default:
|
||||
ShowUsageAndExit(true);
|
||||
}
|
||||
}
|
||||
if (optind == argc) ShowUsageAndExit(true);
|
||||
}
|
||||
|
||||
void AddSocket(const struct Socket *s) {
|
||||
struct pollfd pfd;
|
||||
pfd.fd = s->fd;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
CHECK_NE(-1L, append(&g_sockets, s));
|
||||
CHECK_NE(-1L, append(&g_polls, &pfd));
|
||||
}
|
||||
|
||||
void RemoveSocket(size_t i) {
|
||||
DCHECK_LT(i, g_sockets.i);
|
||||
LOGF("removing: %s", gc(DescribeSocket(&g_sockets.p[i])));
|
||||
CHECK_NE(-1, close(g_sockets.p[i].fd));
|
||||
while (g_sockets.p[i].egress.i) {
|
||||
free(g_sockets.p[i].egress.p[g_sockets.p[i].egress.i - 1].data.iov_base);
|
||||
}
|
||||
memcpy(&g_sockets.p[i], &g_sockets.p[i + 1],
|
||||
(intptr_t)&g_sockets.p[g_sockets.i] - (intptr_t)&g_sockets.p[i + 1]);
|
||||
memcpy(&g_polls.p[i], &g_polls.p[i + 1],
|
||||
(intptr_t)&g_polls.p[g_polls.i] - (intptr_t)&g_polls.p[i + 1]);
|
||||
g_sockets.i--;
|
||||
g_polls.i--;
|
||||
}
|
||||
|
||||
void GetListeningAddressesFromCommandLine(int argc, char *argv[]) {
|
||||
int i;
|
||||
for (i = optind; i < argc; ++i) {
|
||||
struct Socket server;
|
||||
memset(&server, 0, sizeof(server));
|
||||
char scheme[4];
|
||||
unsigned char *ip4 = (unsigned char *)&server.addr.sin_addr.s_addr;
|
||||
uint16_t port;
|
||||
if (sscanf(argv[i], "%3s:%hhu.%hhu.%hhu.%hhu:%hu", scheme, &ip4[0], &ip4[1],
|
||||
&ip4[2], &ip4[3], &port) != 6) {
|
||||
fprintf(stderr, "error: bad ip4 uri\n");
|
||||
ShowUsageAndExit(true);
|
||||
}
|
||||
server.fd = -1;
|
||||
server.kind = kSocketServer;
|
||||
server.addr.sin_family = AF_INET;
|
||||
server.addr.sin_port = htons(port);
|
||||
if (strcasecmp(scheme, "tcp") == 0) {
|
||||
server.type = SOCK_STREAM;
|
||||
server.protocol = IPPROTO_TCP;
|
||||
} else if (strcasecmp(scheme, "udp") == 0) {
|
||||
server.type = SOCK_DGRAM;
|
||||
server.protocol = IPPROTO_UDP;
|
||||
} else {
|
||||
fprintf(stderr, "%s: %s\n", "error", "bad scheme (should be tcp or udp)");
|
||||
ShowUsageAndExit(true);
|
||||
}
|
||||
AddSocket(&server);
|
||||
}
|
||||
}
|
||||
|
||||
void BeginListeningForIncomingTraffic(void) {
|
||||
size_t i;
|
||||
for (i = 0; i < g_sockets.i; ++i) {
|
||||
int yes = 1;
|
||||
struct Socket *s = &g_sockets.p[i];
|
||||
CHECK_NE(-1L,
|
||||
(g_polls.p[i].fd = s->fd = socket(
|
||||
s->addr.sin_family, s->type | SOCK_NONBLOCK, s->protocol)));
|
||||
CHECK_NE(-1L,
|
||||
setsockopt(s->fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)));
|
||||
CHECK_NE(-1, bind(s->fd, &s->addr, sizeof(s->addr)));
|
||||
if (s->protocol == IPPROTO_TCP) {
|
||||
CHECK_NE(-1, listen(s->fd, 1));
|
||||
}
|
||||
uint32_t addrsize = sizeof(s->addr);
|
||||
CHECK_NE(-1, getsockname(s->fd, &s->addr, &addrsize));
|
||||
LOGF("listening on %s", gc(DescribeSocket(s)));
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptConnection(size_t i) {
|
||||
struct Socket *server = &g_sockets.p[i];
|
||||
struct Socket client;
|
||||
memset(&client, 0, sizeof(client));
|
||||
client.kind = kSocketClient;
|
||||
client.type = server->type;
|
||||
client.protocol = server->protocol;
|
||||
uint32_t addrsize = sizeof(client.addr);
|
||||
CHECK_NE(-1L, (client.fd = accept4(server->fd, &client.addr, &addrsize,
|
||||
SOCK_NONBLOCK)));
|
||||
LOGF("%s accepted %s", gc(DescribeSocket(server)),
|
||||
gc(DescribeSocket(&client)));
|
||||
AddSocket(&client);
|
||||
}
|
||||
|
||||
bool ReceiveData(size_t i) {
|
||||
ssize_t got;
|
||||
struct Message msg;
|
||||
bool isudp = g_sockets.p[i].protocol == IPPROTO_UDP;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.destsize = sizeof(msg.dest);
|
||||
msg.data.iov_len = PAGESIZE;
|
||||
msg.data.iov_base = xmalloc(msg.data.iov_len);
|
||||
CHECK_NE(-1L, (got = recvfrom(g_sockets.p[i].fd, msg.data.iov_base,
|
||||
msg.data.iov_len, 0, isudp ? &msg.dest : NULL,
|
||||
isudp ? &msg.destsize : NULL)));
|
||||
if (0 < got && got <= msg.data.iov_len) {
|
||||
LOGF("%s received %lu bytes from %s", gc(DescribeSocket(&g_sockets.p[i])),
|
||||
got, gc(DescribeAddress(&msg.dest)));
|
||||
msg.data.iov_base = xrealloc(msg.data.iov_base, (msg.data.iov_len = got));
|
||||
append(&g_sockets.p[i].egress, &msg);
|
||||
g_polls.p[i].events |= POLLOUT;
|
||||
return true;
|
||||
} else {
|
||||
RemoveSocket(i);
|
||||
free_s(&msg.data.iov_base);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SendData(size_t i) {
|
||||
ssize_t sent;
|
||||
struct Socket *s = &g_sockets.p[i];
|
||||
struct Message *msg = &s->egress.p[s->egress.i - 1];
|
||||
bool isudp = s->protocol == IPPROTO_UDP;
|
||||
DCHECK(s->egress.i);
|
||||
CHECK_NE(-1L, (sent = sendto(s->fd, msg->data.iov_base, msg->data.iov_len, 0,
|
||||
isudp ? &msg->dest : NULL,
|
||||
isudp ? msg->destsize : 0)));
|
||||
LOGF("%s sent %lu bytes to %s", gc(DescribeSocket(s)), msg->data.iov_len,
|
||||
gc(DescribeAddress(&msg->dest)));
|
||||
if (!(msg->data.iov_len -= min((size_t)sent, (size_t)msg->data.iov_len))) {
|
||||
free_s(&msg->data.iov_base);
|
||||
if (!--s->egress.i) {
|
||||
g_polls.p[i].events &= ~POLLOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleSomeNetworkTraffic(void) {
|
||||
size_t i;
|
||||
int eventcount;
|
||||
CHECK_GE((eventcount = poll(g_polls.p, g_polls.i, -1)), 0);
|
||||
for (i = 0; eventcount && i < g_sockets.i; ++i) {
|
||||
if (!g_polls.p[i].revents) continue;
|
||||
--eventcount;
|
||||
if (g_polls.p[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
||||
CHECK_EQ(kSocketClient, g_sockets.p[i].kind);
|
||||
RemoveSocket(i);
|
||||
} else {
|
||||
if (g_polls.p[i].revents & POLLIN) {
|
||||
if (g_sockets.p[i].kind == kSocketServer &&
|
||||
g_sockets.p[i].protocol == IPPROTO_TCP) {
|
||||
AcceptConnection(i);
|
||||
} else {
|
||||
if (!ReceiveData(i)) continue;
|
||||
}
|
||||
}
|
||||
if (g_polls.p[i].revents & POLLOUT) {
|
||||
SendData(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EchoServer(void) {
|
||||
for (;;) HandleSomeNetworkTraffic();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
STATIC_YOINK("isatty");
|
||||
GetFlags(argc, argv);
|
||||
GetListeningAddressesFromCommandLine(argc, argv);
|
||||
BeginListeningForIncomingTraffic();
|
||||
struct InterruptibleCall icall;
|
||||
memset(&icall, 0, sizeof(icall));
|
||||
interruptiblecall(&icall, (void *)EchoServer, 0, 0, 0, 0);
|
||||
fputc('\r', stderr);
|
||||
LOGF("%s", "shutting down...");
|
||||
size_t i;
|
||||
for (i = g_sockets.i; i; --i) RemoveSocket(i - 1);
|
||||
return 0;
|
||||
}
|
56
tool/net/net.mk
Normal file
56
tool/net/net.mk
Normal file
|
@ -0,0 +1,56 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_NET
|
||||
|
||||
TOOL_NET_FILES := $(wildcard tool/net/*)
|
||||
TOOL_NET_SRCS = $(filter %.c,$(TOOL_NET_FILES))
|
||||
TOOL_NET_HDRS = $(filter %.h,$(TOOL_NET_FILES))
|
||||
TOOL_NET_COMS = $(TOOL_NET_OBJS:%.o=%.com)
|
||||
|
||||
TOOL_NET_OBJS = \
|
||||
$(TOOL_NET_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(TOOL_NET_SRCS:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_NET_BINS = \
|
||||
$(TOOL_NET_COMS) \
|
||||
$(TOOL_NET_COMS:%=%.dbg)
|
||||
|
||||
TOOL_NET_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_GETOPT \
|
||||
TOOL_DECODE_LIB
|
||||
|
||||
TOOL_NET_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_NET_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/tool/net/net.pkg: \
|
||||
$(TOOL_NET_OBJS) \
|
||||
$(foreach x,$(TOOL_NET_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/tool/net/%.com.dbg: \
|
||||
$(TOOL_NET_DEPS) \
|
||||
o/$(MODE)/tool/net/%.o \
|
||||
o/$(MODE)/tool/net/net.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
$(TOOL_NET_OBJS): \
|
||||
$(BUILD_FILES) \
|
||||
tool/net/net.mk
|
||||
|
||||
.PHONY: o/$(MODE)/tool/net
|
||||
o/$(MODE)/tool/net: $(TOOL_NET_BINS) $(TOOL_NET_CHECKS)
|
230
tool/scripts/asmexpr
Executable file
230
tool/scripts/asmexpr
Executable file
|
@ -0,0 +1,230 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# OVERVIEW
|
||||
#
|
||||
# Micro-experiment assembler.
|
||||
#
|
||||
# EXAMPLES
|
||||
#
|
||||
# asmexpr 'mov $-4096,%rax' 'not %rax' 'bsr %rax,%rax'
|
||||
# asmexpr 'mov $0,%ecx' 'vmovd %ecx,%xmm1' 'vpbroadcastb %xmm1,%ymm1' 'mov $0x20202032489001ff,%rax' 'vmovq %rax,%xmm0' 'vpcmpgtb %ymm1,%ymm0,%ymm2'
|
||||
|
||||
c=/tmp/asmexpr.c
|
||||
s1=/tmp/asmexpr1.s
|
||||
s2=/tmp/asmexpr2.s
|
||||
s3=/tmp/asmexpr3.s
|
||||
x=/tmp/asmexpr.exe
|
||||
|
||||
cat <<EOF >$s1
|
||||
.comm rsp,8
|
||||
.globl funk
|
||||
funk: push %rbp
|
||||
mov %rsp,%rbp
|
||||
push %rbx
|
||||
push %r12
|
||||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
mov %rsp,rsp(%rip)
|
||||
xor %eax,%eax
|
||||
xor %ebx,%ebx
|
||||
xor %ecx,%ecx
|
||||
xor %edx,%edx
|
||||
xor %edi,%edi
|
||||
xor %esi,%esi
|
||||
xor %r8d,%r8d
|
||||
xor %r9d,%r9d
|
||||
xor %r10d,%r10d
|
||||
xor %r11d,%r11d
|
||||
xor %r12d,%r12d
|
||||
xor %r13d,%r13d
|
||||
xor %r14d,%r14d
|
||||
xor %r15d,%r15d
|
||||
vzeroall
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
EOF
|
||||
|
||||
cat <<EOF >$s2
|
||||
.comm a,8
|
||||
.comm b,8
|
||||
.comm c,8
|
||||
.comm x,8
|
||||
.comm y,8
|
||||
.comm z,8
|
||||
EOF
|
||||
for i; do
|
||||
cat <<EOF >>$s2
|
||||
$i
|
||||
EOF
|
||||
done
|
||||
|
||||
cat <<EOF >$s3
|
||||
.comm rsp,8
|
||||
.comm regs,14*8
|
||||
.comm flags,4
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
cld
|
||||
mov rsp(%rip),%rsp
|
||||
push %rbx
|
||||
lea regs(%rip),%rbx
|
||||
mov %rax,0(%rbx)
|
||||
pop %rax
|
||||
mov %rax,8(%rbx)
|
||||
mov %rcx,16(%rbx)
|
||||
mov %rdx,24(%rbx)
|
||||
mov %rdi,32(%rbx)
|
||||
mov %rsi,40(%rbx)
|
||||
mov %r8,48(%rbx)
|
||||
mov %r9,56(%rbx)
|
||||
mov %r10,64(%rbx)
|
||||
mov %r11,72(%rbx)
|
||||
mov %r12,80(%rbx)
|
||||
mov %r13,88(%rbx)
|
||||
mov %r14,96(%rbx)
|
||||
mov %r15,104(%rbx)
|
||||
vmovaps %ymm0,0x0a0(%rbx)
|
||||
vmovaps %ymm1,0x0c0(%rbx)
|
||||
vmovaps %ymm2,0x0e0(%rbx)
|
||||
vmovaps %ymm3,0x100(%rbx)
|
||||
vmovaps %ymm4,0x120(%rbx)
|
||||
vmovaps %ymm5,0x140(%rbx)
|
||||
vmovaps %ymm6,0x160(%rbx)
|
||||
vmovaps %ymm7,0x180(%rbx)
|
||||
vmovaps %ymm8,0x1a0(%rbx)
|
||||
vmovaps %ymm9,0x1c0(%rbx)
|
||||
vmovaps %ymm10,0x1e0(%rbx)
|
||||
vmovaps %ymm11,0x200(%rbx)
|
||||
vmovaps %ymm12,0x220(%rbx)
|
||||
vmovaps %ymm13,0x240(%rbx)
|
||||
vmovaps %ymm14,0x260(%rbx)
|
||||
vmovaps %ymm15,0x280(%rbx)
|
||||
pushf
|
||||
pop %rax
|
||||
mov %eax,flags(%rip)
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
pop %r12
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
vzeroupper
|
||||
ret
|
||||
EOF
|
||||
|
||||
cat <<EOF >$c
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
struct GodHatesFlags {
|
||||
unsigned c : 1; /* bit 0: carry flag */
|
||||
unsigned v : 1; /* bit 1: V flag: was 8085 signed-number overflow */
|
||||
unsigned p : 1; /* bit 2: parity flag */
|
||||
unsigned r : 1; /* bit 3: always zero */
|
||||
unsigned a : 1; /* bit 4: auxiliary flag (nibble carry) */
|
||||
unsigned k : 1; /* bit 5: K is for Kompressor (K = V flag ⊕ sgn(result)) */
|
||||
unsigned z : 1; /* bit 6: zero flag */
|
||||
unsigned s : 1; /* bit 7: sign flag */
|
||||
unsigned t : 1; /* bit 8: it's a trap flag */
|
||||
unsigned i : 1; /* bit 9: interrupt enable flag */
|
||||
unsigned d : 1; /* bit 10: direction flag */
|
||||
unsigned o : 1; /* bit 11: overflow flag */
|
||||
unsigned pl : 2; /* b12-13: i/o privilege level (80286+) */
|
||||
unsigned nt : 1; /* bit 14: nested task flag (80286+) */
|
||||
unsigned pc : 1; /* bit 15: oldskool flag */
|
||||
unsigned blah : 16;
|
||||
unsigned blah2 : 32;
|
||||
};
|
||||
|
||||
char *DescribeFlags(struct GodHatesFlags flags) {
|
||||
static char buf[256];
|
||||
buf[0] = 0;
|
||||
if (flags.c) strcat(buf, "CF ");
|
||||
if (flags.p) strcat(buf, "PF ");
|
||||
if (flags.a) strcat(buf, "AF ");
|
||||
if (flags.z) strcat(buf, "ZF ");
|
||||
if (flags.s) strcat(buf, "SF ");
|
||||
if (flags.t) strcat(buf, "TF ");
|
||||
if (flags.i) strcat(buf, "IF ");
|
||||
if (flags.d) strcat(buf, "DF ");
|
||||
if (flags.o) strcat(buf, "OF ");
|
||||
strcat(buf, "IOPL-");
|
||||
switch (flags.pl) {
|
||||
case 0:
|
||||
strcat(buf, "0");
|
||||
break;
|
||||
case 1:
|
||||
strcat(buf, "1");
|
||||
break;
|
||||
case 2:
|
||||
strcat(buf, "2");
|
||||
break;
|
||||
case 3:
|
||||
strcat(buf, "3");
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
strcat(buf, " ");
|
||||
if (flags.nt) strcat(buf, "NT ");
|
||||
if (flags.r || flags.k || flags.pc) {
|
||||
strcat(buf, "[WOW: ");
|
||||
if (flags.v) strcat(buf, "VF ");
|
||||
if (flags.k) strcat(buf, "KF ");
|
||||
if (flags.r) strcat(buf, "RF ");
|
||||
if (flags.pc) strcat(buf, "PC ");
|
||||
strcat(buf, "] ");
|
||||
}
|
||||
return &buf[0];
|
||||
}
|
||||
|
||||
void funk();
|
||||
struct GodHatesFlags flags;
|
||||
struct {
|
||||
long gen[14];
|
||||
long __pad[6];
|
||||
unsigned long ymms[16][4];
|
||||
} regs;
|
||||
static const char regnames[][4] = {"rax", "rbx", "rcx", "rdx", "rdi", "rsi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"};
|
||||
int main() {
|
||||
funk();
|
||||
printf("flags %45s\n\n", DescribeFlags(flags));
|
||||
for (unsigned i = 0; i < 14; ++i) {
|
||||
if (regs.gen[i]) {
|
||||
printf("%s s 0x%08x %20d\\n", regnames[i], (signed)(regs.gen[i]), (signed)(regs.gen[i]));
|
||||
printf(" u 0x%08x %20u\\n", (unsigned)(regs.gen[i]), (unsigned)(regs.gen[i]));
|
||||
printf(" sll 0x%016llx %20lld\\n", (signed long long)(regs.gen[i]), (signed long long)(regs.gen[i]));
|
||||
printf(" ull 0x%016llx %20llu\\n", (unsigned long long)(regs.gen[i]), (unsigned long long)(regs.gen[i]));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < 16; ++i) {
|
||||
if (regs.ymms[i][0] || regs.ymms[i][1] || regs.ymms[i][2] || regs.ymms[i][3]) {
|
||||
printf("ymm%d%s %016lx%016lx%016lx%016lx\\n", i, i < 10 ? " " : "", regs.ymms[i][3], regs.ymms[i][2], regs.ymms[i][1], regs.ymms[i][0]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
cc -c -g -o $c.o $c &&
|
||||
cc -c -g -o $s1.o $s1 &&
|
||||
cc -c -g -o $s2.o $s2 &&
|
||||
cc -c -g -o $s3.o $s3 &&
|
||||
cc -g -o $x $c $s1.o $s2.o $s3.o && {
|
||||
echo
|
||||
objdump -d $s2.o | sed 1,7d
|
||||
echo
|
||||
$x
|
||||
}
|
||||
|
||||
exit
|
8
tool/scripts/find-autonomous-objects
Executable file
8
tool/scripts/find-autonomous-objects
Executable file
|
@ -0,0 +1,8 @@
|
|||
#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐
|
||||
#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘
|
||||
|
||||
for f; do
|
||||
if [ $(nm $f | grep ' U ' | wc -l) -eq 0 ]; then
|
||||
echo $f
|
||||
fi
|
||||
done
|
4
tool/scripts/ressurect-file
Executable file
4
tool/scripts/ressurect-file
Executable file
|
@ -0,0 +1,4 @@
|
|||
#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐
|
||||
#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘
|
||||
|
||||
git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "${1:?FILE}"
|
12
tool/tool.mk
Normal file
12
tool/tool.mk
Normal file
|
@ -0,0 +1,12 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
.PHONY: o/$(MODE)/tool
|
||||
o/$(MODE)/tool: \
|
||||
o/$(MODE)/tool/build \
|
||||
o/$(MODE)/tool/debug \
|
||||
o/$(MODE)/tool/decode \
|
||||
o/$(MODE)/tool/hash \
|
||||
o/$(MODE)/tool/net \
|
||||
o/$(MODE)/tool/viz \
|
||||
o/$(MODE)/tool/cc
|
121
tool/viz/ascii2utf8.c
Normal file
121
tool/viz/ascii2utf8.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
@fileoverview Converts ASCII combining marks to UNICODE.
|
||||
|
||||
Getting started:
|
||||
|
||||
nroff -mandoc -rLL=72n -rLT=78n -Tutf8 <manpage.1 |
|
||||
tool/viz/ascii2utf8.com
|
||||
|
||||
ASCII Bold:
|
||||
|
||||
- CHAR BACKSPACE CHAR c ++ "\b" ++ c
|
||||
e.g. AABBCCDD 410841 420842 430843 440844
|
||||
|
||||
ASCII Underlines:
|
||||
|
||||
- CHAR BACKSPACE LOW LINE c ++ "\b_"
|
||||
e.g. A_B_C_D_ 41085F 42085F 43085F 44085F
|
||||
|
||||
UNICODE Underlines:
|
||||
|
||||
- COMBINING LOW LINE U+0332 (\xCC\xB1)
|
||||
e.g. A̲B̲C̲D̲ (ugly notches) 41CCB2 42CCB2 43CCB2 44CCB2
|
||||
|
||||
- COMBINING MACRON BELOW U+0331 (\xCC\xB1)
|
||||
e.g. A̱ḆC̱Ḏ (too short) 41CCB1 42CCB1 43CCB1 44CCB1
|
||||
|
||||
- COMBINING DOUBLE MACRON BELOW U+035F (\xCD\x9F)
|
||||
e.g. A͟B͟C͟D͟ (too long) 41CD9F 42CD9F 43CD9F 44CD9F
|
||||
|
||||
- DOUBLE PLUS COMBINING MACRON BELOW 3×U+035F + 1×U+0331
|
||||
e.g. A͟B͟C͟Ḏ (too narrow) 41CCB1 42CCB1 43CCB1 44CD9F
|
||||
|
||||
- DOUBLE PLUS COMBINING MACRON LOW LINE [it's complicated]
|
||||
e.g. A͟B͟C͟D̲ (𝑓𝑙𝑎𝑤𝑙𝑒𝑠𝑠) 41CD9F 42CD9F 43CD9F 44CCB2
|
||||
|
||||
*/
|
||||
|
||||
const wint_t kBackspace = '\b';
|
||||
const wint_t kCombiningLowLine = L'\u0332';
|
||||
const wint_t kCombiningDoubleMacronBelow = L'\u035f';
|
||||
|
||||
forceinline int PutChar(wint_t (*buf)[3], size_t *i, wint_t *cc, FILE *out) {
|
||||
if (fputwc((*buf)[0], out) == -1) return -1;
|
||||
if (*cc != -1) {
|
||||
if (fputwc(*cc, out) == -1) return -1;
|
||||
*cc = -1;
|
||||
}
|
||||
(*buf)[0] = (*buf)[1];
|
||||
(*buf)[1] = (*buf)[2];
|
||||
--*i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CombineAsciiMarks(FILE *in, FILE *out) {
|
||||
wint_t buf[3], wc = 0, cc = -1;
|
||||
size_t i = 0;
|
||||
for (;;) {
|
||||
while (i < 3) {
|
||||
if ((wc = fgetwc(in)) == -1) goto InputBreak;
|
||||
buf[i++] = wc;
|
||||
}
|
||||
if (buf[1] == '\b' && cc == -1) {
|
||||
if (buf[0] == buf[2]) { /* bold */
|
||||
if (L'0' <= buf[0] && buf[0] <= L'9') {
|
||||
buf[0] = L'𝟬' + (buf[0] - L'0');
|
||||
i = 1;
|
||||
} else if (L'A' <= buf[0] && buf[0] <= L'Z') {
|
||||
buf[0] = L'𝐀' + (buf[0] - L'A');
|
||||
i = 1;
|
||||
} else if ('a' <= buf[0] && buf[0] <= L'z') {
|
||||
buf[0] = L'𝗮' + (buf[0] - L'a');
|
||||
i = 1;
|
||||
} else {
|
||||
i = 1;
|
||||
}
|
||||
} else if (buf[2] == '_') { /* underline */
|
||||
cc = kCombiningLowLine;
|
||||
i = 1;
|
||||
} else if (buf[0] == '_') {
|
||||
cc = kCombiningLowLine;
|
||||
buf[0] = buf[2];
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
if (i == 3) {
|
||||
if (PutChar(&buf, &i, &cc, out) == -1) goto OutputBreak;
|
||||
}
|
||||
}
|
||||
InputBreak:
|
||||
while (i) {
|
||||
if (PutChar(&buf, &i, &cc, out) == -1) goto OutputBreak;
|
||||
}
|
||||
OutputBreak:
|
||||
return (fclose(in) | fclose(out)) != -1 ? 0 : -1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return CombineAsciiMarks(stdin, stdout) != -1 ? 0 : errno;
|
||||
}
|
265
tool/viz/basicidea.c
Normal file
265
tool/viz/basicidea.c
Normal file
|
@ -0,0 +1,265 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/spawn.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
#define SQR(X) ((X) * (X))
|
||||
#define DIST(X, Y) ((X) - (Y))
|
||||
|
||||
static int want24bit_;
|
||||
|
||||
const int kXtermCube[] = {0, 0137, 0207, 0257, 0327, 0377};
|
||||
|
||||
static int rgbdist(int a, int b, int c, int x, int y, int z) {
|
||||
return SQR(DIST(a, x)) + SQR(DIST(b, y)) + SQR(DIST(c, z));
|
||||
}
|
||||
|
||||
static int uncube(int x) {
|
||||
return x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40;
|
||||
}
|
||||
|
||||
static int DivideIntRound(int x, int y) {
|
||||
return (x + y / 2) / y;
|
||||
}
|
||||
|
||||
static int XtermQuantizeLuma(int Y) {
|
||||
return DivideIntRound(Y - 8, 10);
|
||||
}
|
||||
|
||||
static int XtermDequantizeLuma(int qY) {
|
||||
if (0 < qY && qY < 24) {
|
||||
return (qY * 10) + 8;
|
||||
} else if (qY > 0) {
|
||||
return 255;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int XtermEncodeLuma(int qY) {
|
||||
if (0 < qY && qY < 24) {
|
||||
return qY + 232;
|
||||
} else if (qY > 0) {
|
||||
return 231;
|
||||
} else {
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
static int XtermQuantizeChroma(int c) {
|
||||
return DivideIntRound(c - 55, 40);
|
||||
}
|
||||
|
||||
static int XtermDequantizeChroma(int qc) {
|
||||
if (0 < qc && qc < 6) {
|
||||
return (qc * 40) + 55;
|
||||
} else if (qc > 0) {
|
||||
return 255;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int XtermEncodeChromaComponent(int qC) {
|
||||
if (0 < qC && qC < 6) {
|
||||
return qC;
|
||||
} else if (qC > 0) {
|
||||
return 5;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int XtermEncodeChroma(int qR, int qG, int qB) {
|
||||
int xt;
|
||||
xt = 16;
|
||||
xt += XtermEncodeChromaComponent(qR) * 6 * 6;
|
||||
xt += XtermEncodeChromaComponent(qG) * 6;
|
||||
xt += XtermEncodeChromaComponent(qB) * 1;
|
||||
return xt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quantizes 24-bit sRGB to xterm256 code range [16,256).
|
||||
*/
|
||||
static int rgb2xterm256(unsigned char R, unsigned char G, unsigned char B) {
|
||||
double y, r, g, b, yr, yg, yb, ry, gy, by, gamma;
|
||||
int Y, qY, cY, qRY, qGY, qBY, qR, qG, qB, cR, cG, cB, xt;
|
||||
gamma = 2.4;
|
||||
yr = 871024 / 4096299.;
|
||||
yg = 8788810 / 12288897.;
|
||||
yb = 887015 / 12288897.;
|
||||
r = rgb2linpc(R / 255., gamma);
|
||||
g = rgb2linpc(G / 255., gamma);
|
||||
b = rgb2linpc(B / 255., gamma);
|
||||
y = yr * r + yg * g + yb * b;
|
||||
ry = (r - y) / (1 - yr + yg + yb);
|
||||
gy = (g - y) / (1 - yg + yr + yb);
|
||||
by = (b - y) / (1 - yb + yg + yr);
|
||||
Y = round(rgb2stdpc(y, gamma) * 255);
|
||||
qRY = round(rgb2stdpc(ry, gamma) * 6 + 3);
|
||||
qGY = round(rgb2stdpc(gy, gamma) * 6 + 3);
|
||||
qBY = round(rgb2stdpc(by, gamma) * 6 + 3);
|
||||
qY = XtermQuantizeLuma(Y);
|
||||
qR = XtermQuantizeChroma(qRY);
|
||||
qG = XtermQuantizeChroma(qGY);
|
||||
qB = XtermQuantizeChroma(qBY);
|
||||
cY = XtermDequantizeLuma(qY);
|
||||
cR = XtermDequantizeChroma(qRY);
|
||||
cG = XtermDequantizeChroma(qGY);
|
||||
cB = XtermDequantizeChroma(qBY);
|
||||
#if 0
|
||||
LOGF("RGB(%3d,%3d,%3d) rgb(%f,%f,%f) y=%f", R, G, B, r, g, b, y);
|
||||
LOGF("RGB(%3d,%3d,%3d) yΔrgb(%f,%f,%f) XCUBE(%d,%d,%d)", R, G, B, ry, gy, by,
|
||||
qRY, qGY, qBY);
|
||||
LOGF("RGB(%3d,%3d,%3d) cRGB(%d,%d,%d) cY=%d qY=%d Y=%d", R, G, B, cR, cG, cB,
|
||||
cY, qY, Y);
|
||||
#endif
|
||||
if (rgbdist(cR, cG, cB, R, G, B) <= rgbdist(cY, cY, cY, R, G, B)) {
|
||||
xt = XtermEncodeChroma(qR, qG, qB);
|
||||
} else {
|
||||
xt = XtermEncodeLuma(qY);
|
||||
}
|
||||
/* LOGF("xt=%d", xt); */
|
||||
return xt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints raw packed 8-bit RGB data from memory.
|
||||
*/
|
||||
static void PrintImage(long yn, long xn, unsigned char RGB[yn][xn][4]) {
|
||||
long y, x;
|
||||
for (y = 0; y < yn; y += 2) {
|
||||
if (y) printf("\r\n");
|
||||
for (x = 0; x < xn; ++x) {
|
||||
if (want24bit_) {
|
||||
printf("\033[48;2;%hhu;%hhu;%hhu;38;2;%hhu;%hhu;%hhum▄",
|
||||
RGB[y + 0][x][0], RGB[y + 0][x][1], RGB[y + 0][x][2],
|
||||
RGB[y + 1][x][0], RGB[y + 1][x][1], RGB[y + 1][x][2]);
|
||||
} else {
|
||||
printf(
|
||||
"\033[48;5;%hhu;38;5;%hhum▄",
|
||||
rgb2xterm256(RGB[y + 0][x][0], RGB[y + 0][x][1], RGB[y + 0][x][2]),
|
||||
rgb2xterm256(RGB[y + 1][x][0], RGB[y + 1][x][1], RGB[y + 1][x][2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsWindows()) {
|
||||
printf("\033[0m\r\n");
|
||||
} else {
|
||||
printf("\033[0m\r");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines dimensions of teletypewriter.
|
||||
*/
|
||||
static void GetTermSize(unsigned *out_rows, unsigned *out_cols) {
|
||||
struct winsize ws;
|
||||
ws.ws_row = 20;
|
||||
ws.ws_col = 80;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
|
||||
ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
|
||||
*out_rows = ws.ws_row;
|
||||
*out_cols = ws.ws_col;
|
||||
}
|
||||
|
||||
static void ReadAll(int fd, void *buf, size_t n) {
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
size_t got;
|
||||
p = buf;
|
||||
do {
|
||||
CHECK_NE(-1, (rc = read(fd, p, n)));
|
||||
got = rc;
|
||||
CHECK(!(!got && n));
|
||||
p += got;
|
||||
n -= got;
|
||||
} while (n);
|
||||
}
|
||||
|
||||
static void LoadImageOrDie(const char *path, size_t size, long yn, long xn,
|
||||
unsigned char RGB[yn][xn][4]) {
|
||||
int pid, ws, fds[3];
|
||||
const char *convert;
|
||||
if (isempty((convert = getenv("CONVERT"))) &&
|
||||
!(IsWindows() && access((convert = "\\msys64\\mingw64\\bin\\convert.exe"),
|
||||
X_OK) != -1) &&
|
||||
!(convert = commandv("convert"))) {
|
||||
fputs("'convert' command not found\r\n"
|
||||
"please install imagemagick\r\n",
|
||||
stderr);
|
||||
exit(1);
|
||||
}
|
||||
fds[0] = STDIN_FILENO;
|
||||
fds[1] = -1;
|
||||
fds[2] = STDERR_FILENO;
|
||||
pid = spawnve(0, fds, convert,
|
||||
(char *const[]){"convert", path, "-resize",
|
||||
gc(xasprintf("%ux%u!", xn, yn)), "-colorspace",
|
||||
"RGB", "-depth", "8", "rgba:-", NULL},
|
||||
environ);
|
||||
CHECK_NE(-1, pid);
|
||||
ReadAll(fds[1], RGB, size);
|
||||
CHECK_NE(-1, close(fds[1]));
|
||||
CHECK_NE(-1, waitpid(pid, &ws, 0));
|
||||
CHECK_EQ(0, WEXITSTATUS(ws));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
void *rgb;
|
||||
size_t size;
|
||||
unsigned yn, xn;
|
||||
cancolor();
|
||||
GetTermSize(&yn, &xn);
|
||||
yn *= 2;
|
||||
size = yn * xn * 4;
|
||||
CHECK_NOTNULL((rgb = valloc(size)));
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "-t") == 0) {
|
||||
want24bit_ = 1;
|
||||
} else {
|
||||
LoadImageOrDie(argv[i], size, yn, xn, rgb);
|
||||
PrintImage(yn, xn, rgb);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
44
tool/viz/bin2asm.c
Normal file
44
tool/viz/bin2asm.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define COLS 8
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int c, col = 0;
|
||||
unsigned char ch;
|
||||
char16_t glyphs[COLS + 1];
|
||||
while ((c = getchar()) != -1) {
|
||||
if (col == 0) {
|
||||
printf("\t.byte\t");
|
||||
memset(glyphs, 0, sizeof(glyphs));
|
||||
}
|
||||
ch = c & 0xff;
|
||||
glyphs[col] = kCp437[ch];
|
||||
if (col) putchar(',');
|
||||
printf("0x%02x", ch);
|
||||
if (++col == COLS) {
|
||||
col = 0;
|
||||
printf("\t#%hs\n", glyphs);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
93
tool/viz/bing.c
Normal file
93
tool/viz/bing.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Bing: Binary → Glyphs.
|
||||
* Intended for oldskool data science.
|
||||
*/
|
||||
|
||||
int ispipe_;
|
||||
int newlines_;
|
||||
|
||||
noreturn void ShowUsage(FILE *f, int rc) {
|
||||
fputs(program_invocation_name, f);
|
||||
fputs(": [-p] [-n] [FILE...]\n", f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "hpn")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
ispipe_ = true;
|
||||
break;
|
||||
case 'n':
|
||||
newlines_ = true;
|
||||
break;
|
||||
case 'h':
|
||||
ShowUsage(stdout, EXIT_SUCCESS);
|
||||
default:
|
||||
ShowUsage(stderr, EX_USAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bing(FILE *f) {
|
||||
int c, c2;
|
||||
while ((c = fgetc(f)) != -1) {
|
||||
c2 = c == '\n' && newlines_ ? '\n' : kCp437[c & 0xff];
|
||||
if (ispipe_) {
|
||||
fputc(c, stdout);
|
||||
fputwc(c2, stderr);
|
||||
} else {
|
||||
fputwc(c2, stdout);
|
||||
}
|
||||
}
|
||||
fputc('\n', ispipe_ ? stderr : stdout);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *f;
|
||||
size_t i;
|
||||
GetOpts(argc, argv);
|
||||
if (optind < argc) {
|
||||
for (i = optind; i < argc; ++i) {
|
||||
if (!(f = fopen(argv[i], "rb"))) {
|
||||
perror(argv[i]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
bing(f);
|
||||
fclose(f);
|
||||
}
|
||||
} else {
|
||||
bing(stdin);
|
||||
}
|
||||
return 0;
|
||||
}
|
104
tool/viz/comma.c
Normal file
104
tool/viz/comma.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define USAGE \
|
||||
" [FLAGS] [PATH|FLEXDEC...] [<<<FLEXDEC...\\n...]\n\
|
||||
Turns numbers into decimal with commas.\n\
|
||||
\n\
|
||||
Values are tokenized by spaces. Anything that isn't an integer is\n\
|
||||
passed through. We parse integers the same way the C compiler does\n\
|
||||
so 0x,0b,0,etc. prefixes are fine. Unicode spacing characters are\n\
|
||||
supported.\n\
|
||||
\n\
|
||||
Flags:\n\
|
||||
-o PATH output path\n\
|
||||
-F STR\n\
|
||||
-T STR sets field tokenization charset [default is whitespace]\n\
|
||||
-w FLEXDEC\n\
|
||||
-n FLEXDEC set fixed number of columns [default is variable, based\n\
|
||||
on line breaks]\n\
|
||||
-?\n\
|
||||
-h shows this information\n\
|
||||
\n"
|
||||
|
||||
static size_t linecap_;
|
||||
static FILE *in_, *out_;
|
||||
static const char16_t *fieldtoks_;
|
||||
static char *inpath_, *outpath_, *line_;
|
||||
|
||||
void PrintUsage(int rc, FILE *f) {
|
||||
fputs("Usage: ", f);
|
||||
fputs(program_invocation_name, f);
|
||||
fputs(USAGE, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int *argc, char *argv[]) {
|
||||
int opt;
|
||||
outpath_ = "-";
|
||||
fieldtoks_ = u" \t\v\n\r\f ";
|
||||
while ((opt = getopt(*argc, argv, "?ho:F:T:w:n:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
outpath_ = optarg;
|
||||
break;
|
||||
case 'F':
|
||||
case 'T':
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
if (optind == *argc) {
|
||||
argv[(*argc)++] = "-";
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessFile(void) {
|
||||
while ((getline(&line_, &linecap_, in_)) != -1) {
|
||||
// TODO(jart)
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
size_t i;
|
||||
GetOpts(&argc, argv);
|
||||
CHECK_NOTNULL((out_ = fopen(outpath_, "w")));
|
||||
for (i = optind; i < argc; ++i) {
|
||||
CHECK_NOTNULL((in_ = fopen((inpath_ = argv[i]), "r")));
|
||||
ProcessFile();
|
||||
CHECK_NE(-1, fclose_s(&in_));
|
||||
}
|
||||
CHECK_NE(-1, fclose_s(&out_));
|
||||
free(line_);
|
||||
return 0;
|
||||
}
|
322
tool/viz/cpuid.c
Normal file
322
tool/viz/cpuid.c
Normal file
|
@ -0,0 +1,322 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/cpuid4.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/rdtscp.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/nexgen32e/x86info.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/decode/lib/idname.h"
|
||||
#include "tool/decode/lib/x86idnames.h"
|
||||
|
||||
#define RED (cancolor() ? "\x1b[91m" : "")
|
||||
#define GREEN (cancolor() ? "\x1b[32m" : "")
|
||||
#define RESET (cancolor() ? "\x1b[0m" : "")
|
||||
#define CANIUSE(FEATURE) caniuse(#FEATURE, X86_HAVE(FEATURE))
|
||||
#define SHOW(CONSTANT) show(#CONSTANT, CONSTANT)
|
||||
|
||||
static void caniuse(const char *feature, bool present) {
|
||||
printf("%-20s%s%s%s\n", feature, present ? GREEN : RED,
|
||||
present ? "present" : "unavailable", RESET);
|
||||
}
|
||||
|
||||
static void show(const char *constant, long value) {
|
||||
printf("%-20s%#lx\n", constant, value);
|
||||
}
|
||||
|
||||
static void showvendor(void) {
|
||||
printf("%.*s%.*s%.*s", 4, &KCPUIDS(0H, EBX), 4, &KCPUIDS(0H, EDX), 4,
|
||||
&KCPUIDS(0H, ECX));
|
||||
}
|
||||
|
||||
static void showmodel(void) {
|
||||
if (getx86processormodel(kX86ProcessorModelKey)) {
|
||||
printf(" %s",
|
||||
findnamebyid(kX86MarchNames,
|
||||
getx86processormodel(kX86ProcessorModelKey)->march));
|
||||
}
|
||||
}
|
||||
|
||||
static void showspeed(void) {
|
||||
if (KCPUIDS(16H, EAX)) {
|
||||
printf(" %.1f%s", KCPUIDS(16H, EAX) / 1000.0, "ghz");
|
||||
}
|
||||
}
|
||||
|
||||
static void showstrata(void) {
|
||||
if (getx86processormodel(kX86ProcessorModelKey)) {
|
||||
printf(" (%s %s)",
|
||||
findnamebyid(kX86GradeNames,
|
||||
getx86processormodel(kX86ProcessorModelKey)->grade),
|
||||
"Grade");
|
||||
}
|
||||
}
|
||||
|
||||
void showcachesizes(void) {
|
||||
unsigned i;
|
||||
CPUID4_ITERATE(i, {
|
||||
printf("%-19s%s%s %u-way %,7u byte cache w/%s %,5u sets of %u byte lines "
|
||||
"shared across %u threads\n",
|
||||
gc(xasprintf("Level %u%s", CPUID4_CACHE_LEVEL,
|
||||
CPUID4_CACHE_TYPE == 1
|
||||
? " data"
|
||||
: CPUID4_CACHE_TYPE == 2 ? " code" : "")),
|
||||
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
|
||||
CPUID4_COMPLEX_INDEXING ? " complexly-indexed" : "",
|
||||
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
|
||||
CPUID4_PHYSICAL_LINE_PARTITIONS > 1
|
||||
? gc(xasprintf(" %u physically partitioned"))
|
||||
: "",
|
||||
CPUID4_NUMBER_OF_SETS, CPUID4_SYSTEM_COHERENCY_LINE_SIZE,
|
||||
CPUID4_MAX_THREADS_SHARING_CACHE);
|
||||
});
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
long tsc_aux;
|
||||
|
||||
showvendor();
|
||||
showmodel();
|
||||
showspeed();
|
||||
showstrata();
|
||||
printf("\n");
|
||||
|
||||
if (X86_HAVE(HYPERVISOR)) {
|
||||
unsigned eax, ebx, ecx, edx;
|
||||
asm("push\t%%rbx\n\t"
|
||||
"cpuid\n\t"
|
||||
"mov\t%%ebx,%1\n\t"
|
||||
"pop\t%%rbx"
|
||||
: "=a"(eax), "=rm"(ebx), "=c"(ecx), "=d"(edx)
|
||||
: "0"(0x40000000), "2"(0));
|
||||
printf("Running inside %.4s%.4s%.4s (eax=%#x)\n", &ebx, &ecx, &edx, eax);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
SHOW(kX86CpuStepping);
|
||||
SHOW(kX86CpuModelid);
|
||||
SHOW(kX86CpuFamilyid);
|
||||
SHOW(kX86CpuType);
|
||||
SHOW(kX86CpuExtmodelid);
|
||||
SHOW(kX86CpuExtfamilyid);
|
||||
|
||||
printf("\n");
|
||||
tsc_aux = rdpid();
|
||||
show("TSC_AUX", tsc_aux);
|
||||
show(" → core", TSC_AUX_CORE(tsc_aux));
|
||||
show(" → node", TSC_AUX_NODE(tsc_aux));
|
||||
|
||||
printf("\n");
|
||||
printf("Caches\n");
|
||||
printf("──────\n");
|
||||
showcachesizes();
|
||||
|
||||
printf("\n");
|
||||
printf("Features\n");
|
||||
printf("────────\n");
|
||||
CANIUSE(ACC);
|
||||
CANIUSE(ACPI);
|
||||
CANIUSE(ADX);
|
||||
CANIUSE(AES);
|
||||
CANIUSE(APIC);
|
||||
CANIUSE(ARCH_CAPABILITIES);
|
||||
CANIUSE(AVX);
|
||||
|
||||
printf("%-20s%s%s%s%s\n", "AVX2", X86_HAVE(AVX2) ? GREEN : RED,
|
||||
X86_HAVE(AVX2) ? "present" : "unavailable", RESET,
|
||||
(!X86_HAVE(AVX2) && ({
|
||||
unsigned eax, ebx, ecx, edx;
|
||||
asm("push\t%%rbx\n\t"
|
||||
"cpuid\n\t"
|
||||
"mov\t%%ebx,%1\n\t"
|
||||
"pop\t%%rbx"
|
||||
: "=a"(eax), "=rm"(ebx), "=c"(ecx), "=d"(edx)
|
||||
: "0"(7), "2"(0));
|
||||
(void)eax;
|
||||
(void)ecx;
|
||||
(void)edx;
|
||||
!!(ebx & (1u << 5));
|
||||
}))
|
||||
? " (disabled by operating system)"
|
||||
: "");
|
||||
|
||||
CANIUSE(AVX512BW);
|
||||
CANIUSE(AVX512CD);
|
||||
CANIUSE(AVX512DQ);
|
||||
CANIUSE(AVX512ER);
|
||||
CANIUSE(AVX512F);
|
||||
CANIUSE(AVX512IFMA);
|
||||
CANIUSE(AVX512PF);
|
||||
CANIUSE(AVX512VBMI);
|
||||
CANIUSE(AVX512VL);
|
||||
CANIUSE(AVX512_4FMAPS);
|
||||
CANIUSE(AVX512_4VNNIW);
|
||||
CANIUSE(AVX512_BF16);
|
||||
CANIUSE(AVX512_BITALG);
|
||||
CANIUSE(AVX512_VBMI2);
|
||||
CANIUSE(AVX512_VNNI);
|
||||
CANIUSE(AVX512_VP2INTERSECT);
|
||||
CANIUSE(AVX512_VPOPCNTDQ);
|
||||
CANIUSE(BMI);
|
||||
CANIUSE(BMI2);
|
||||
CANIUSE(CID);
|
||||
CANIUSE(CLDEMOTE);
|
||||
CANIUSE(CLFLUSH);
|
||||
CANIUSE(CLFLUSHOPT);
|
||||
CANIUSE(CLWB);
|
||||
CANIUSE(CMOV);
|
||||
CANIUSE(CQM);
|
||||
CANIUSE(CX16);
|
||||
CANIUSE(CX8);
|
||||
CANIUSE(DCA);
|
||||
CANIUSE(DE);
|
||||
CANIUSE(DS);
|
||||
CANIUSE(DSCPL);
|
||||
CANIUSE(DTES64);
|
||||
CANIUSE(ERMS);
|
||||
CANIUSE(EST);
|
||||
CANIUSE(F16C);
|
||||
CANIUSE(FDP_EXCPTN_ONLY);
|
||||
CANIUSE(FLUSH_L1D);
|
||||
CANIUSE(FMA);
|
||||
CANIUSE(FPU);
|
||||
CANIUSE(FSGSBASE);
|
||||
CANIUSE(FXSR);
|
||||
CANIUSE(GBPAGES);
|
||||
CANIUSE(GFNI);
|
||||
CANIUSE(HLE);
|
||||
CANIUSE(HT);
|
||||
CANIUSE(HYPERVISOR);
|
||||
CANIUSE(IA64);
|
||||
CANIUSE(INTEL_PT);
|
||||
CANIUSE(INTEL_STIBP);
|
||||
CANIUSE(INVPCID);
|
||||
CANIUSE(LA57);
|
||||
CANIUSE(LM);
|
||||
CANIUSE(MCA);
|
||||
CANIUSE(MCE);
|
||||
CANIUSE(MD_CLEAR);
|
||||
CANIUSE(MMX);
|
||||
CANIUSE(MOVBE);
|
||||
CANIUSE(MOVDIR64B);
|
||||
CANIUSE(MOVDIRI);
|
||||
CANIUSE(MP);
|
||||
CANIUSE(MPX);
|
||||
CANIUSE(MSR);
|
||||
CANIUSE(MTRR);
|
||||
CANIUSE(MWAIT);
|
||||
CANIUSE(NX);
|
||||
CANIUSE(OSPKE);
|
||||
CANIUSE(OSXSAVE);
|
||||
CANIUSE(PAE);
|
||||
CANIUSE(PAT);
|
||||
CANIUSE(PBE);
|
||||
CANIUSE(PCID);
|
||||
CANIUSE(PCLMUL);
|
||||
CANIUSE(PCONFIG);
|
||||
CANIUSE(PDCM);
|
||||
CANIUSE(PGE);
|
||||
CANIUSE(PKU);
|
||||
CANIUSE(PN);
|
||||
CANIUSE(POPCNT);
|
||||
CANIUSE(PSE);
|
||||
CANIUSE(PSE36);
|
||||
CANIUSE(RDPID);
|
||||
CANIUSE(RDRND);
|
||||
CANIUSE(RDSEED);
|
||||
CANIUSE(RDTSCP);
|
||||
CANIUSE(RDT_A);
|
||||
CANIUSE(RTM);
|
||||
CANIUSE(SDBG);
|
||||
CANIUSE(SELFSNOOP);
|
||||
CANIUSE(SEP);
|
||||
CANIUSE(SHA);
|
||||
CANIUSE(SMAP);
|
||||
CANIUSE(SMEP);
|
||||
CANIUSE(SMX);
|
||||
CANIUSE(SPEC_CTRL);
|
||||
CANIUSE(SPEC_CTRL_SSBD);
|
||||
CANIUSE(SSE);
|
||||
CANIUSE(SSE2);
|
||||
CANIUSE(SSE3);
|
||||
CANIUSE(SSE4_1);
|
||||
CANIUSE(SSE4_2);
|
||||
CANIUSE(SSSE3);
|
||||
CANIUSE(SYSCALL);
|
||||
CANIUSE(TM2);
|
||||
CANIUSE(TME);
|
||||
CANIUSE(TSC);
|
||||
CANIUSE(TSC_ADJUST);
|
||||
CANIUSE(TSC_DEADLINE_TIMER);
|
||||
CANIUSE(TSX_FORCE_ABORT);
|
||||
CANIUSE(UMIP);
|
||||
CANIUSE(VAES);
|
||||
CANIUSE(VME);
|
||||
CANIUSE(VMX);
|
||||
CANIUSE(VPCLMULQDQ);
|
||||
CANIUSE(WAITPKG);
|
||||
CANIUSE(X2APIC);
|
||||
CANIUSE(XSAVE);
|
||||
CANIUSE(XTPR);
|
||||
CANIUSE(ZERO_FCS_FDS);
|
||||
|
||||
printf("\n");
|
||||
printf("AMD Stuff\n");
|
||||
printf("─────────\n");
|
||||
CANIUSE(3DNOW);
|
||||
CANIUSE(3DNOWEXT);
|
||||
CANIUSE(3DNOWPREFETCH);
|
||||
CANIUSE(ABM);
|
||||
CANIUSE(BPEXT);
|
||||
CANIUSE(CMP_LEGACY);
|
||||
CANIUSE(CR8_LEGACY);
|
||||
CANIUSE(EXTAPIC);
|
||||
CANIUSE(FMA4);
|
||||
CANIUSE(FXSR_OPT);
|
||||
CANIUSE(IBS);
|
||||
CANIUSE(LAHF_LM);
|
||||
CANIUSE(LWP);
|
||||
CANIUSE(MISALIGNSSE);
|
||||
CANIUSE(MMXEXT);
|
||||
CANIUSE(MWAITX);
|
||||
CANIUSE(NODEID_MSR);
|
||||
CANIUSE(OSVW);
|
||||
CANIUSE(OVERFLOW_RECOV);
|
||||
CANIUSE(PERFCTR_CORE);
|
||||
CANIUSE(PERFCTR_LLC);
|
||||
CANIUSE(PERFCTR_NB);
|
||||
CANIUSE(PTSC);
|
||||
CANIUSE(SKINIT);
|
||||
CANIUSE(SMCA);
|
||||
CANIUSE(SSE4A);
|
||||
CANIUSE(SUCCOR);
|
||||
CANIUSE(SVM);
|
||||
CANIUSE(TBM);
|
||||
CANIUSE(TCE);
|
||||
CANIUSE(TOPOEXT);
|
||||
CANIUSE(WDT);
|
||||
CANIUSE(XOP);
|
||||
|
||||
return 0;
|
||||
}
|
149
tool/viz/deathstar.c
Normal file
149
tool/viz/deathstar.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
#include "dsp/tty/tty.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* @fileoverview demo code borrowed from Rosetta Code.
|
||||
*/
|
||||
|
||||
#define FRAMERATE 23.976
|
||||
|
||||
struct Sphere {
|
||||
double cx, cy, cz, r;
|
||||
};
|
||||
|
||||
const char *kShades[] = {
|
||||
"\e[48;5;232m ", "\e[48;5;233m ", "\e[48;5;234m ", "\e[48;5;235m ",
|
||||
"\e[48;5;236m ", "\e[48;5;237m ", "\e[48;5;238m ", "\e[48;5;239m ",
|
||||
"\e[48;5;240m ", "\e[48;5;241m ", "\e[48;5;242m ", "\e[48;5;243m ",
|
||||
"\e[48;5;244m ", "\e[48;5;245m ", "\e[48;5;246m ", "\e[48;5;247m ",
|
||||
"\e[48;5;248m ", "\e[48;5;249m ", "\e[48;5;250m ", "\e[48;5;251m ",
|
||||
"\e[48;5;252m ", "\e[48;5;253m ", "\e[48;5;254m ", "\e[48;5;255m ",
|
||||
};
|
||||
|
||||
jmp_buf jb_;
|
||||
double light_[3] = {-50, 0, 50};
|
||||
struct Sphere pos_ = {20, 20, 20, 20};
|
||||
struct Sphere neg_ = {1, 1, -6, 20};
|
||||
|
||||
static void OnCtrlC(int sig) {
|
||||
longjmp(jb_, 1);
|
||||
}
|
||||
|
||||
static void Normalize(double v[3]) {
|
||||
double len;
|
||||
len = 1 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
v[0] *= len;
|
||||
v[1] *= len;
|
||||
v[2] *= len;
|
||||
}
|
||||
|
||||
static double Dot(const double x[3], const double y[3]) {
|
||||
return fabs(x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
|
||||
}
|
||||
|
||||
/* check if a ray (x,y, -inf)->(x, y, inf) hits a sphere; if so, return
|
||||
the intersecting z values. z1 is closer to the eye */
|
||||
static int HitSphere(struct Sphere *s, double x, double y, double z[2]) {
|
||||
double zsq;
|
||||
x -= s->cx;
|
||||
y -= s->cy;
|
||||
zsq = s->r * s->r - (x * x + y * y);
|
||||
if (zsq < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
zsq = sqrt(zsq);
|
||||
z[0] = s->cz - zsq;
|
||||
z[1] = s->cz + zsq;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawSphere(double k, double ambient) {
|
||||
int i, j, hit_result;
|
||||
double x, y, vec[3], zb[2], zs[2];
|
||||
for (i = floor(pos_.cy - pos_.r); i <= ceil(pos_.cy + pos_.r); i++) {
|
||||
y = i + .5;
|
||||
for (j = floor(pos_.cx - 2 * pos_.r); j <= ceil(pos_.cx + 2 * pos_.r);
|
||||
j++) {
|
||||
x = .5 * (j - pos_.cx) + .5 + pos_.cx;
|
||||
if (!HitSphere(&pos_, x, y, zb)) {
|
||||
/* ray lands in blank space, draw bg */
|
||||
hit_result = 0;
|
||||
} else if (!HitSphere(&neg_, x, y, zs)) {
|
||||
/* ray hits pos_ sphere but not neg_, draw pos_ sphere surface */
|
||||
hit_result = 1;
|
||||
} else if (zs[0] > zb[0]) {
|
||||
/* ray hits both, but pos_ front surface is closer */
|
||||
hit_result = 1;
|
||||
} else if (zs[1] > zb[1]) {
|
||||
/* pos_ sphere surface is inside neg_ sphere, show bg */
|
||||
hit_result = 0;
|
||||
} else if (zs[1] > zb[0]) {
|
||||
/* back surface on neg_ sphere is inside pos_ sphere,
|
||||
the only place where neg_ sphere surface will be shown */
|
||||
hit_result = 2;
|
||||
} else {
|
||||
hit_result = 1;
|
||||
}
|
||||
switch (hit_result) {
|
||||
case 0:
|
||||
fputs("\e[0m ", stdout);
|
||||
continue;
|
||||
case 1:
|
||||
vec[0] = x - pos_.cx;
|
||||
vec[1] = y - pos_.cy;
|
||||
vec[2] = zb[0] - pos_.cz;
|
||||
break;
|
||||
default:
|
||||
vec[0] = neg_.cx - x;
|
||||
vec[1] = neg_.cy - y;
|
||||
vec[2] = neg_.cz - zs[1];
|
||||
break;
|
||||
}
|
||||
Normalize(vec);
|
||||
fputs(
|
||||
kShades[MIN(ARRAYLEN(kShades) - 1,
|
||||
MAX(0, lround((1 - (pow(Dot(light_, vec), k) + ambient)) *
|
||||
(ARRAYLEN(kShades) - 1))))],
|
||||
stdout);
|
||||
}
|
||||
fputs("\e[0m\n", stdout);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int main() {
|
||||
double ang;
|
||||
struct termios old;
|
||||
if (cancolor()) {
|
||||
ttyhidecursor(fileno(stdout));
|
||||
if (!setjmp(jb_)) {
|
||||
xsigaction(SIGINT, OnCtrlC, 0, 0, NULL);
|
||||
ang = 0;
|
||||
for (;;) {
|
||||
printf("\e[H");
|
||||
light_[1] = cos(ang * 2);
|
||||
light_[2] = cos(ang);
|
||||
light_[0] = sin(ang);
|
||||
Normalize(light_);
|
||||
ang += .05;
|
||||
DrawSphere(1.5, .01);
|
||||
usleep(1. / FRAMERATE * 1e6);
|
||||
}
|
||||
}
|
||||
ttyshowcursor(fileno(stdout));
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
619
tool/viz/derasterize.c
Normal file
619
tool/viz/derasterize.c
Normal file
|
@ -0,0 +1,619 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/spawn.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/avir/lanczos.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/stb/stb_image.h"
|
||||
#include "third_party/stb/stb_image_resize.h"
|
||||
|
||||
#define HELPTEXT \
|
||||
"\n\
|
||||
NAME\n\
|
||||
\n\
|
||||
derasterize - convert pictures to text using unicode ANSI art\n\
|
||||
\n\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
derasterize [FLAGS] [PNG|JPG|ETC]...\n\
|
||||
\n\
|
||||
DESCRIPTION\n\
|
||||
\n\
|
||||
This program converts pictures into unicode text and ANSI colors so\n\
|
||||
that images can be displayed within a terminal. It performs lots of\n\
|
||||
AVX2 optimized math to deliver the best quality on modern terminals\n\
|
||||
with 24-bit color support, e.g. Kitty, Gnome Terminal, CMD.EXE, etc\n\
|
||||
\n\
|
||||
The default output if fullscreen but can be changed:\n\
|
||||
-w X\n\
|
||||
-x X\n\
|
||||
If X is positive, hardcode the width in tty cells to X\n\
|
||||
If X is negative, remove as much from the fullscreen width\n\
|
||||
X may be specified as base 10 decimal, octal, binary, or hex\n\
|
||||
-h Y\n\
|
||||
-y Y\n\
|
||||
If Y is positive, hardcode the height in tty cells to Y\n\
|
||||
If Y is negative, remove as much from the fullscreen height\n\
|
||||
May be specified as base 10 decimal, octal, binary, or hex\n\
|
||||
-m\n\
|
||||
Use ImageMagick `convert` command to load/scale graphics\n\
|
||||
-?\n\
|
||||
-H\n\
|
||||
Show this help information\n\
|
||||
\n\
|
||||
EXAMPLES\n\
|
||||
\n\
|
||||
$ ./derasterize.com samples/wave.png > wave.uaart\n\
|
||||
$ cat wave.uaart\n\
|
||||
\n\
|
||||
AUTHORS\n\
|
||||
\n\
|
||||
Csdvrx <csdvrx@outlook.com>\n\
|
||||
Justine Tunney <jtunney@gmail.com>\n\
|
||||
"
|
||||
|
||||
int m_; /* -m [use imagemagick] */
|
||||
int x_; /* -x WIDTH [in flexidecimal] */
|
||||
int y_; /* -y HEIGHT [in flexidecimal] */
|
||||
|
||||
#define BEST 0
|
||||
#define FAST 1
|
||||
#define FASTER 2
|
||||
|
||||
#define MODE BEST
|
||||
|
||||
#if MODE == BEST
|
||||
#define MC 9u /* log2(#) of color combos to consider */
|
||||
#define GN 35u /* # of glyphs to consider */
|
||||
#elif MODE == FAST
|
||||
#define MC 6u
|
||||
#define GN 35u
|
||||
#elif MODE == FASTER
|
||||
#define MC 4u
|
||||
#define GN 25u
|
||||
#endif
|
||||
|
||||
#define CN 3u /* # channels (rgb) */
|
||||
#define YS 8u /* row stride -or- block height */
|
||||
#define XS 4u /* column stride -or- block width */
|
||||
#define GT 44u /* total glyphs */
|
||||
#define BN (YS * XS) /* # scalars in block/glyph plane */
|
||||
|
||||
#define PHIPRIME 0x9E3779B1u
|
||||
|
||||
extern const uint32_t kGlyphs[];
|
||||
extern const char16_t kRunes[];
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ derasterize § encoding ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
/**
|
||||
* Formats Thompson-Pike variable length integer to array.
|
||||
*
|
||||
* @param p needs at least 8 bytes
|
||||
* @return p + number of bytes written, cf. mempcpy
|
||||
* @note no NUL-terminator is added
|
||||
*/
|
||||
static char *tptoa(char *p, wchar_t x) {
|
||||
unsigned long w;
|
||||
for (w = tpenc(x); w; w >>= 010) *p++ = w & 0xff;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ derasterize § colors ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
static float frgb2lin(float x) {
|
||||
float r1, r2;
|
||||
r1 = x / 12.92f;
|
||||
r2 = pow((x + 0.055) / (1 + 0.055), 2.4);
|
||||
return x < 0.04045f ? r1 : r2;
|
||||
}
|
||||
|
||||
static float frgb2std(float x) {
|
||||
float r1, r2;
|
||||
r1 = x * 12.92f;
|
||||
r2 = 1.055 * pow(x, 1 / 2.4) - 0.055;
|
||||
return x < 0.0031308f ? r1 : r2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts 8-bit RGB samples to floating point.
|
||||
*/
|
||||
static void rgb2float(unsigned n, float *f, const unsigned char *u) {
|
||||
unsigned i;
|
||||
for (i = 0; i < n; ++i) f[i] = u[i];
|
||||
for (i = 0; i < n; ++i) f[i] /= 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts floating point RGB samples to 8-bit.
|
||||
*/
|
||||
static void float2rgb(unsigned n, unsigned char *u, float *f) {
|
||||
unsigned i;
|
||||
for (i = 0; i < n; ++i) f[i] *= 256;
|
||||
for (i = 0; i < n; ++i) f[i] = roundf(f[i]);
|
||||
for (i = 0; i < n; ++i) u[i] = MAX(0, MIN(255, f[i]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts standard RGB to linear RGB.
|
||||
*
|
||||
* This makes subtraction look good by flattening out the bias curve
|
||||
* that PC display manufacturers like to use.
|
||||
*/
|
||||
static noinline void rgb2lin(unsigned n, float *f, const unsigned char *u) {
|
||||
unsigned i;
|
||||
rgb2float(n, f, u);
|
||||
for (i = 0; i < n; ++i) f[i] = frgb2lin(f[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts linear RGB to standard RGB.
|
||||
*/
|
||||
static noinline void rgb2std(unsigned n, unsigned char *u, float *f) {
|
||||
unsigned i;
|
||||
for (i = 0; i < n; ++i) f[i] = frgb2std(f[i]);
|
||||
float2rgb(n, u, f);
|
||||
}
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ derasterize § blocks ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
struct Cell {
|
||||
char16_t rune;
|
||||
unsigned char bg[CN], fg[CN];
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializes ANSI background, foreground, and UNICODE glyph to wire.
|
||||
*/
|
||||
static char *celltoa(char *p, struct Cell cell) {
|
||||
*p++ = 033;
|
||||
*p++ = '[';
|
||||
*p++ = '4';
|
||||
*p++ = '8';
|
||||
*p++ = ';';
|
||||
*p++ = '2';
|
||||
*p++ = ';';
|
||||
p = itoa8(p, cell.bg[0]);
|
||||
*p++ = ';';
|
||||
p = itoa8(p, cell.bg[1]);
|
||||
*p++ = ';';
|
||||
p = itoa8(p, cell.bg[2]);
|
||||
*p++ = ';';
|
||||
*p++ = '3';
|
||||
*p++ = '8';
|
||||
*p++ = ';';
|
||||
*p++ = '2';
|
||||
*p++ = ';';
|
||||
p = itoa8(p, cell.fg[0]);
|
||||
*p++ = ';';
|
||||
p = itoa8(p, cell.fg[1]);
|
||||
*p++ = ';';
|
||||
p = itoa8(p, cell.fg[2]);
|
||||
*p++ = 'm';
|
||||
p = tptoa(p, cell.rune);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks ≤2**MC unique (bg,fg) pairs from product of lb.
|
||||
*/
|
||||
static unsigned combinecolors(unsigned char bf[1u << MC][2],
|
||||
const unsigned char bl[CN][YS * XS]) {
|
||||
uint64_t hv, ht[(1u << MC) * 2];
|
||||
unsigned i, j, n, b, f, h, hi, bu, fu;
|
||||
memset(ht, 0, sizeof(ht));
|
||||
for (n = b = 0; b < BN && n < (1u << MC); ++b) {
|
||||
bu = bl[2][b] << 020 | bl[1][b] << 010 | bl[0][b];
|
||||
hi = 0;
|
||||
hi = (((bu >> 000) & 0xff) + hi) * PHIPRIME;
|
||||
hi = (((bu >> 010) & 0xff) + hi) * PHIPRIME;
|
||||
hi = (((bu >> 020) & 0xff) + hi) * PHIPRIME;
|
||||
for (f = b + 1; f < BN && n < (1u << MC); ++f) {
|
||||
fu = bl[2][f] << 020 | bl[1][f] << 010 | bl[0][f];
|
||||
h = hi;
|
||||
h = (((fu >> 000) & 0xff) + h) * PHIPRIME;
|
||||
h = (((fu >> 010) & 0xff) + h) * PHIPRIME;
|
||||
h = (((fu >> 020) & 0xff) + h) * PHIPRIME;
|
||||
h = h & 0xffff;
|
||||
h = MAX(1, h);
|
||||
hv = 0;
|
||||
hv <<= 030;
|
||||
hv |= fu;
|
||||
hv <<= 030;
|
||||
hv |= bu;
|
||||
hv <<= 020;
|
||||
hv |= h;
|
||||
for (i = 0;; ++i) {
|
||||
j = (h + i * (i + 1) / 2) & (ARRAYLEN(ht) - 1);
|
||||
if (!ht[j]) {
|
||||
ht[j] = hv;
|
||||
bf[n][0] = b;
|
||||
bf[n][1] = f;
|
||||
n++;
|
||||
break;
|
||||
} else if (ht[j] == hv) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes distance between synthetic block and actual.
|
||||
*/
|
||||
#define ADJUDICATE(SYMBOL, ARCH) \
|
||||
ARCH static float SYMBOL(unsigned b, unsigned f, unsigned g, \
|
||||
const float lb[CN][YS * XS]) { \
|
||||
unsigned i, k, gu; \
|
||||
float p[BN], q[BN], fu, bu, r; \
|
||||
memset(q, 0, sizeof(q)); \
|
||||
for (k = 0; k < CN; ++k) { \
|
||||
gu = kGlyphs[g]; \
|
||||
bu = lb[k][b]; \
|
||||
fu = lb[k][f]; \
|
||||
for (i = 0; i < BN; ++i) p[i] = (gu & (1u << i)) ? fu : bu; \
|
||||
for (i = 0; i < BN; ++i) p[i] -= lb[k][i]; \
|
||||
for (i = 0; i < BN; ++i) p[i] *= p[i]; \
|
||||
for (i = 0; i < BN; ++i) q[i] += p[i]; \
|
||||
} \
|
||||
r = 0; \
|
||||
for (i = 0; i < BN; ++i) q[i] = sqrtf(q[i]); \
|
||||
for (i = 0; i < BN; ++i) r += q[i]; \
|
||||
return r; \
|
||||
}
|
||||
|
||||
ADJUDICATE(adjudicate$avx2, microarchitecture("avx2,fma"))
|
||||
ADJUDICATE(adjudicate$avx, microarchitecture("avx"))
|
||||
ADJUDICATE(adjudicate$default, )
|
||||
|
||||
static float (*adjudicate$hook)(unsigned, unsigned, unsigned,
|
||||
const float[CN][YS * XS]);
|
||||
|
||||
static float adjudicate2(unsigned b, unsigned f, unsigned g,
|
||||
const float lb[CN][YS * XS]) {
|
||||
if (!adjudicate$hook) {
|
||||
if (X86_HAVE(AVX2) && X86_HAVE(FMA)) {
|
||||
adjudicate$hook = adjudicate$avx2;
|
||||
} else if (X86_HAVE(AVX)) {
|
||||
adjudicate$hook = adjudicate$avx;
|
||||
} else {
|
||||
adjudicate$hook = adjudicate$default;
|
||||
}
|
||||
}
|
||||
return adjudicate$hook(b, f, g, lb);
|
||||
}
|
||||
|
||||
static float adjudicate(unsigned b, unsigned f, unsigned g,
|
||||
const float lb[CN][YS * XS]) {
|
||||
unsigned i, k, gu;
|
||||
float p[BN], q[BN], fu, bu, r;
|
||||
memset(q, 0, sizeof(q));
|
||||
for (k = 0; k < CN; ++k) {
|
||||
gu = kGlyphs[g];
|
||||
bu = lb[k][b];
|
||||
fu = lb[k][f];
|
||||
for (i = 0; i < BN; ++i) p[i] = (gu & (1u << i)) ? fu : bu;
|
||||
for (i = 0; i < BN; ++i) p[i] -= lb[k][i];
|
||||
for (i = 0; i < BN; ++i) p[i] *= p[i];
|
||||
for (i = 0; i < BN; ++i) q[i] += p[i];
|
||||
}
|
||||
r = 0;
|
||||
for (i = 0; i < BN; ++i) q[i] = sqrtf(q[i]);
|
||||
for (i = 0; i < BN; ++i) r += q[i];
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts tiny bitmap graphic into unicode glyph.
|
||||
*/
|
||||
static struct Cell derasterize(unsigned char block[CN][YS * XS]) {
|
||||
struct Cell cell;
|
||||
unsigned i, n, b, f, g;
|
||||
float r, best, lb[CN][YS * XS];
|
||||
unsigned char bf[1u << MC][2];
|
||||
rgb2lin(CN * YS * XS, lb[0], block[0]);
|
||||
n = combinecolors(bf, block);
|
||||
best = -1u;
|
||||
cell.rune = 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
b = bf[i][0];
|
||||
f = bf[i][1];
|
||||
for (g = 0; g < GN; ++g) {
|
||||
r = adjudicate(b, f, g, lb);
|
||||
if (r < best) {
|
||||
best = r;
|
||||
cell.rune = kRunes[g];
|
||||
cell.bg[0] = block[0][b];
|
||||
cell.bg[1] = block[1][b];
|
||||
cell.bg[2] = block[2][b];
|
||||
cell.fg[0] = block[0][f];
|
||||
cell.fg[1] = block[1][f];
|
||||
cell.fg[2] = block[2][f];
|
||||
if (!r) return cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ derasterize § graphics ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
/**
|
||||
* Turns packed 8-bit RGB graphic into ANSI UNICODE text.
|
||||
*/
|
||||
static char *RenderImage(char *v, unsigned yn, unsigned xn,
|
||||
const unsigned char srgb[yn][YS][xn][XS][CN]) {
|
||||
unsigned y, x, i, j, k;
|
||||
unsigned char copy[YS][XS][CN] aligned(32);
|
||||
unsigned char block[CN][YS * XS] aligned(32);
|
||||
DCHECK_ALIGNED(32, v);
|
||||
DCHECK_ALIGNED(32, srgb);
|
||||
for (y = 0; y < yn; ++y) {
|
||||
if (y) {
|
||||
*v++ = 033;
|
||||
*v++ = '[';
|
||||
*v++ = '0';
|
||||
*v++ = 'm';
|
||||
*v++ = '\n';
|
||||
}
|
||||
for (x = 0; x < xn; ++x) {
|
||||
for (i = 0; i < YS; ++i) {
|
||||
memcpy(copy[i], srgb[y][i][x], XS * CN);
|
||||
}
|
||||
for (i = 0; i < YS; ++i) {
|
||||
for (j = 0; j < XS; ++j) {
|
||||
for (k = 0; k < CN; ++k) {
|
||||
block[k][i * XS + j] = copy[i][j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
v = celltoa(v, derasterize(block));
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ derasterize § systems ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
static void PrintImage(unsigned yn, unsigned xn,
|
||||
const unsigned char rgb[yn][YS][xn][XS][CN]) {
|
||||
size_t size;
|
||||
char *v, *vt;
|
||||
size = yn * (xn * (32 + (2 + (1 + 3) * 3) * 2 + 1 + 3)) * 1 + 5 + 1;
|
||||
size = ROUNDUP(size, FRAMESIZE);
|
||||
CHECK_NE(MAP_FAILED, (vt = mapanon(size)));
|
||||
v = RenderImage(vt, yn, xn, rgb);
|
||||
*v++ = '\r';
|
||||
*v++ = 033;
|
||||
*v++ = '[';
|
||||
*v++ = '0';
|
||||
*v++ = 'm';
|
||||
CHECK_NE(-1, xwrite(1, vt, v - vt));
|
||||
CHECK_NE(-1, munmap(vt, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines dimensions of teletypewriter.
|
||||
*/
|
||||
static void GetTermSize(unsigned out_rows[1], unsigned out_cols[1]) {
|
||||
struct winsize ws;
|
||||
ws.ws_row = 24;
|
||||
ws.ws_col = 80;
|
||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) {
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
|
||||
}
|
||||
out_rows[0] = ws.ws_row;
|
||||
out_cols[0] = ws.ws_col;
|
||||
}
|
||||
|
||||
static int ReadAll(int fd, void *data, size_t size) {
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
size_t got, n;
|
||||
p = data;
|
||||
n = size;
|
||||
do {
|
||||
if ((rc = read(fd, p, n)) == -1) return -1;
|
||||
assert((got = rc) || !n);
|
||||
p += got;
|
||||
n -= got;
|
||||
} while (n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and scales image via ImageMagick `convert` command.
|
||||
*
|
||||
* @param path is filename of graphic
|
||||
* @param yn is desired height
|
||||
* @param xn is desired width
|
||||
* @param rgb is memory allocated by caller for image
|
||||
*/
|
||||
static void LoadFileViaImageMagick(const char *path, unsigned yn, unsigned xn,
|
||||
unsigned char rgb[yn][YS][xn][XS][CN]) {
|
||||
const char *convert;
|
||||
int pid, ws, fds[3] = {STDIN_FILENO, -1, STDERR_FILENO};
|
||||
if (!(convert = commandv("convert"))) {
|
||||
fputs("error: `convert` command not found\n"
|
||||
"try: apt-get install imagemagick\n",
|
||||
stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
CHECK_NE(-1,
|
||||
(pid = spawnve(
|
||||
0, fds, convert,
|
||||
(char *const[]){"convert", path, "-resize",
|
||||
xasprintf("%ux%u!", xn * XS, yn * YS), "-depth",
|
||||
"8", "-colorspace", "sRGB", "rgb:-", NULL},
|
||||
environ)));
|
||||
CHECK_NE(-1, ReadAll(fds[STDOUT_FILENO], rgb, yn * YS * xn * XS * CN));
|
||||
CHECK_NE(-1, close(fds[STDOUT_FILENO]));
|
||||
CHECK_NE(-1, waitpid(pid, &ws, 0));
|
||||
CHECK_EQ(0, WEXITSTATUS(ws));
|
||||
}
|
||||
|
||||
static void LoadFile(const char *path, size_t yn, size_t xn, void *rgb) {
|
||||
struct stat st;
|
||||
size_t data2size, data3size;
|
||||
void *map, *data, *data2, *data3;
|
||||
int fd, gotx, goty, channels_in_file;
|
||||
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_GT(st.st_size, 0);
|
||||
CHECK_LE(st.st_size, INT_MAX);
|
||||
LOGIFNEG1(fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL));
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
CHECK_NOTNULL((data = stbi_load_from_memory(map, st.st_size, &gotx, &goty,
|
||||
&channels_in_file, CN)),
|
||||
"%s", path);
|
||||
CHECK_NE(-1, munmap(map, st.st_size));
|
||||
CHECK_NE(-1, close(fd));
|
||||
#if 1
|
||||
stbir_resize_uint8(data, gotx, goty, 0, rgb, xn * XS, yn * YS, 0, CN);
|
||||
#else
|
||||
CHECK_EQ(CN, 3);
|
||||
data2size = ROUNDUP(sizeof(float) * goty * gotx * CN, FRAMESIZE);
|
||||
data3size = ROUNDUP(sizeof(float) * yn * YS * xn * XS * CN, FRAMESIZE);
|
||||
CHECK_NE(MAP_FAILED, (data2 = mapanon(data2size)));
|
||||
CHECK_NE(MAP_FAILED, (data3 = mapanon(data3size)));
|
||||
rgb2lin(goty * gotx * CN, data2, data);
|
||||
lanczos3(yn * YS, xn * XS, data3, goty, gotx, data2, gotx * 3);
|
||||
rgb2std(yn * YS * xn * XS * CN, rgb, data3);
|
||||
CHECK_NE(-1, munmap(data2, data2size));
|
||||
CHECK_NE(-1, munmap(data3, data3size));
|
||||
#endif
|
||||
free(data);
|
||||
}
|
||||
|
||||
static int ParseNumberOption(const char *arg) {
|
||||
long x;
|
||||
x = strtol(arg, NULL, 0);
|
||||
if (!(1 <= x && x <= INT_MAX)) {
|
||||
fprintf(stderr, "invalid flexidecimal: %s\n\n", arg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static void PrintUsage(int rc, FILE *f) {
|
||||
fputs(HELPTEXT, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?Hmx:y:w:h:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'w':
|
||||
case 'x':
|
||||
x_ = ParseNumberOption(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
case 'y':
|
||||
y_ = ParseNumberOption(optarg);
|
||||
break;
|
||||
case 'm':
|
||||
m_ = 1;
|
||||
break;
|
||||
case '?':
|
||||
case 'H':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
void *rgb;
|
||||
size_t size;
|
||||
char *option;
|
||||
unsigned yd, xd;
|
||||
__fast_math();
|
||||
showcrashreports();
|
||||
cancolor();
|
||||
GetOpts(argc, argv);
|
||||
// if sizes are given, 2 cases:
|
||||
// - positive values: use that as the target size
|
||||
// - negative values: add, for ex to offset the command prompt size
|
||||
GetTermSize(&yd, &xd);
|
||||
if (y_ <= 0) {
|
||||
y_ += yd;
|
||||
}
|
||||
if (x_ <= 0) {
|
||||
x_ += xd;
|
||||
}
|
||||
// FIXME: on the conversion stage should do 2Y because of halfblocks
|
||||
// printf( "filename >%s<\tx >%d<\ty >%d<\n\n", filename, x_, y_);
|
||||
size = y_ * YS * x_ * XS * CN;
|
||||
CHECK_NE(MAP_FAILED, (rgb = mapanon(ROUNDUP(size, FRAMESIZE))));
|
||||
for (i = optind; i < argc; ++i) {
|
||||
if (!argv[i]) continue;
|
||||
if (m_) {
|
||||
LoadFileViaImageMagick(argv[i], y_, x_, rgb);
|
||||
} else {
|
||||
LoadFile(argv[i], y_, x_, rgb);
|
||||
}
|
||||
PrintImage(y_, x_, rgb);
|
||||
}
|
||||
munmap(rgb, ROUNDUP(size, FRAMESIZE));
|
||||
return 0;
|
||||
}
|
43
tool/viz/double2int.c
Normal file
43
tool/viz/double2int.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/dtoa/dtoa.h"
|
||||
|
||||
void double2int(const char *s) {
|
||||
double b64;
|
||||
uint64_t u64;
|
||||
b64 = strtod(s, NULL);
|
||||
memcpy(&u64, &b64, 8);
|
||||
printf("0x%016lx\n", u64);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
double2int(argv[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue