Make more improvements

This change includes many bug fixes, for the NT polyfills, strings,
memory, boot, and math libraries which were discovered by adding more
tools for recreational programming, such as PC emulation. Lemon has also
been vendored because it works so well at parsing languages.
This commit is contained in:
Justine Tunney 2020-09-28 01:13:56 -07:00
parent 416fd86676
commit 23d333c090
201 changed files with 14558 additions and 3082 deletions

View file

@ -17,12 +17,6 @@ TOOL_BUILD_OBJS = \
TOOL_BUILD_COMS = \
$(TOOL_BUILD_SRCS:%.c=o/$(MODE)/%.com)
TOOL_BUILD_LINK = \
$(TOOL_BUILD_DEPS) \
o/$(MODE)/tool/build/%.o \
$(CRT) \
$(APE)
TOOL_BUILD_CHECKS = \
$(TOOL_BUILD).pkg \
$(TOOL_BUILD_HDRS:%=o/$(MODE)/%.ok) \
@ -86,24 +80,10 @@ o/$(MODE)/tool/build/%.com.dbg: \
$(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/emulator.o: \
OVERRIDE_COPTS += \
-fno-sanitize=pointer-overflow
o/$(MODE)/tool/build/transpile16.o: \
OVERRIDE_CFLAGS += \
-ffixed-r8 \
-ffixed-r9 \
-ffixed-r10 \
-ffixed-r11 \
-ffixed-r12 \
-ffixed-r13 \
-ffixed-r14 \
-ffixed-r15
.PHONY: o/$(MODE)/tool/build
o/$(MODE)/tool/build: \
o/$(MODE)/tool/build/emucrt \

View file

@ -49,14 +49,15 @@ o/$(MODE)/tool/build/emubin/%.bin.dbg: \
$(TOOL_BUILD_EMUBIN_A).pkg
@$(ELFLINK) -e emucrt -z max-page-size=0x10
o/$(MODE)/tool/build/emubin/real/spiral.o: tool/build/emubin/real/spiral.c
@$(MKDIR) $(@D)
/opt/cross/bin/i486-linux-musl-gcc -nostdlib -nostdinc -m16 -Os -g -c -o $@ $<
o/tiny/tool/build/emubin/spiral.bin.dbg: \
$(TOOL_BUILD_EMUBIN_DEPS) \
o/tiny/tool/build/emubin/spiral.real.o
@$(ELFLINK) -z max-page-size=0x10 -T tool/build/emucrt/real.lds
o/$(MODE)/tool/build/emubin/real/spiral.bin: o/$(MODE)/tool/build/emubin/real/spiral.o
/opt/cross/bin/i486-linux-musl-ld -static -nostdlib --oformat=binary -T tool/build/emubin/real/spiral.lds -o $@ $^
o/$(MODE)/tool/build/emubin/hug.o: OVERRIDE_CFLAGS += -ffast-math
o/tiny/tool/build/emubin/mdatest.bin.dbg: \
$(TOOL_BUILD_EMUBIN_DEPS) \
o/tiny/tool/build/emubin/mdatest.real.o
@$(ELFLINK) -z max-page-size=0x10 -T tool/build/emucrt/real.lds
.PHONY: o/$(MODE)/tool/build/emubin
o/$(MODE)/tool/build/emubin: \

View 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 "tool/build/emubin/poke.h"
#include "tool/build/emubin/real.h"
/*
m=tiny; make -j12 MODE=$m o/$m/tool/build/{tinyemu,emulator}.com \
o/$m/tool/build/emubin/mdatest.bin && o/$m/tool/build/emulator.com \
-rt o/$m/tool/build/emubin/mdatest.bin
*/
static void MdaTest(uint16_t p[25][80]) {
int i, y, x;
for (i = 0; i < 256; ++i) {
y = i / 16;
x = i % 16 * 3;
POKE(p[y][x + 0], i << 8 | "0123456789abcdef"[(i & 0xf0) >> 4]);
POKE(p[y][x + 1], i << 8 | "0123456789abcdef"[(i & 0x0f) >> 0]);
}
}
int main() {
SetVideoMode(7);
SetEs(0xb0000 >> 4);
MdaTest((void *)0);
for (;;) asm("pause");
}

View file

@ -19,7 +19,7 @@
*/
#include "tool/build/emubin/metalsha256.h"
#define DISINGENUOUS /* 100 million NOPs is still 100 MIPS lool */
//#define DISINGENUOUS /* 100 million NOPs is still 100 MIPS lool */
static void Print(uint8_t c) {
asm volatile("out\t%0,$0xE9" : /* no outputs */ : "a"(c) : "memory");

11
tool/build/emubin/poke.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_
#define COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define POKE(MEM, VAL) \
asm volatile("mov\t%1,%%es:%0" : "=m"(MEM) : "Qi"((typeof(MEM))(VAL)))
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_ */

26
tool/build/emubin/real.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_
#define COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
asm(".pushsection .start,\"ax\",@progbits\n\t"
".globl\t_start\n"
"_start:\n\t"
"jmp\t1f\n1:\t"
"call\tmain\n\t"
"nop\n\t"
".popsection");
forceinline void SetEs(int base) {
asm volatile("mov%z0\t%0,%%es" : /* no outputs */ : "r"(base));
}
forceinline void SetVideoMode(int mode) {
asm volatile("int\t$0x10"
: /* no outputs */
: "a"(mode));
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_ */

View file

@ -17,6 +17,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/build/emubin/poke.h"
#include "tool/build/emubin/real.h"
#define signbit(x) __builtin_signbit(x)
@ -38,45 +40,49 @@ static const unsigned char kBlocks[] = {
[0b0001] = 0xdf, // ▀
};
static void *memset(void *di, int al, unsigned long cx) {
asm("rep stosb %%al,(%0)"
forceinline void *memset(void *di, int al, unsigned long cx) {
asm("rep stosb"
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(cx), "a"(al));
return di;
}
static long double pi(void) {
forceinline long double pi(void) {
long double x;
asm("fldpi" : "=t"(x));
return x;
}
static void sincosl(long double x, long double *sin, long double *cos) {
forceinline long double tau(void) {
return pi() * 2;
}
forceinline void sincosl(long double x, long double *sin, long double *cos) {
asm("fsincos" : "=t"(*sin), "=u"(*cos) : "0"(x));
}
static long double atan2l(long double x, long double y) {
forceinline long double atan2l(long double x, long double y) {
asm("fpatan" : "+t"(x) : "u"(y) : "st(1)");
return x;
}
static long lrintl(long double x) {
forceinline long lrintl(long double x) {
long i;
asm("fistp%z0\t%0" : "=m"(i) : "t"(x) : "st");
return i;
}
static long double truncl(long double x) {
forceinline long double truncl(long double x) {
asm("frndint" : "+t"(x));
return x;
}
static long double fabsl(long double x) {
forceinline long double fabsl(long double x) {
asm("fabs" : "+t"(x));
return x;
}
static long lroundl(long double x) {
forceinline long lroundl(long double x) {
int s = signbit(x);
x = truncl(fabsl(x) + .5);
if (s) x = -x;
@ -93,36 +99,40 @@ static void SetFpuControlWord(unsigned short cw) {
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(cw));
}
static void InitializeFpu(void) {
asm("fninit");
}
static void SetTruncationRounding(void) {
SetFpuControlWord(GetFpuControlWord() | 0x0c00);
}
static void spiral(unsigned char p[25][80][2], unsigned char B[25][80]) {
static void spiral(unsigned char p[25][80][2], unsigned char B[25][80], int g) {
int i, x, y;
long double a, b, u, v, h;
for (a = b = i = 0; i < 1000; ++i) {
sincosl(a, &u, &v);
h = atan2l(u, v);
h = atan2l(u, v) - .333L * g;
x = lroundl(80 + u * b);
y = lroundl(25 + v * b * (1. / ((266 / 64.) * (900 / 1600.))));
B[y >> 1][x >> 1] |= 1 << ((y & 1) << 1 | (x & 1));
p[y >> 1][x >> 1][0] = kBlocks[B[y >> 1][x >> 1]];
p[y >> 1][x >> 1][1] = (lrintl((h + pi() * 2) * (8 / (pi() * 2))) & 7) + 8;
POKE(p[y >> 1][x >> 1][0], kBlocks[B[y >> 1][x >> 1]]);
POKE(p[y >> 1][x >> 1][1], (lrintl((h + tau()) * (8 / tau())) & 7) + 8);
a += .05;
b += .05;
}
}
int main() {
asm(".pushsection .start,\"ax\",@progbits\n\t"
".globl\t_start\n"
"_start:\n\t"
"callw\tmain\n\t"
".popsection");
int g;
InitializeFpu();
SetTruncationRounding();
for (;;) {
memset((void *)0x40000, 0, 25 * 80);
memset((void *)0xb8000, 0, 25 * 80 * 2);
spiral((void *)0xb8000, (void *)0x40000);
SetVideoMode(3);
for (g = 0;; ++g) {
SetEs(0);
memset((void *)(0x7c00 + 512), 0, 25 * 80);
SetEs(0xb8000 >> 4);
memset((void *)0, 0, 25 * 80 * 2);
spiral((void *)0, (void *)(0x7c00 + 512), g);
}
}

View file

@ -27,6 +27,8 @@ SECTIONS {
*(.text .text.*)
*(.rodata .rodata.*)
*(.data .data.*)
. = 0x1fe;
SHORT(0xaa55);
*(.bss .bss.*)
*(COMMON)
}

View file

@ -64,13 +64,16 @@
#include "tool/build/lib/breakpoint.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/cga.h"
#include "tool/build/lib/demangle.h"
#include "tool/build/lib/dis.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/fds.h"
#include "tool/build/lib/flags.h"
#include "tool/build/lib/fpu.h"
#include "tool/build/lib/high.h"
#include "tool/build/lib/loader.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/mda.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/panel.h"
@ -176,8 +179,10 @@ static const char kSegmentNames[16][4] = {
static int tyn;
static int txn;
static int tick;
static int speed;
static int vidya;
static int ttyfd;
static bool vidya;
static bool react;
static bool ssehex;
static int exitcode;
@ -200,7 +205,6 @@ static struct Panels pan;
static int64_t readstart;
static int64_t writestart;
static int64_t stackstart;
static struct DisHigh high;
static struct Machine m[2];
static struct MachinePty *pty;
static char logpath[PATH_MAX];
@ -521,6 +525,9 @@ static void SetupDraw(void) {
c2y[1] -= tyn - c2y[2] - 26;
c2y[2] = tyn - 26;
}
if (tyn - c2y[2] < 26) {
c2y[2] = tyn - 26;
}
a = (tyn - (cpuy + ssey) - 3) / 4;
c3y[0] = cpuy;
@ -642,15 +649,11 @@ static void SetupDraw(void) {
xcalloc(pan.p[i].bottom - pan.p[i].top, sizeof(struct Buffer));
}
if (pty->yn != pan.display.bottom - pan.display.top ||
pty->xn != pan.display.right - pan.display.left) {
LOGF("MachinePtyResize");
MachinePtyResize(pty, pan.display.bottom - pan.display.top,
pan.display.right - pan.display.left);
}
MachinePtyResize(pty, pan.display.bottom - pan.display.top,
pan.display.right - pan.display.left);
}
static long GetDisIndex(int64_t addr) {
static long GetDisIndex(void) {
long i;
if ((i = DisFind(dis, GetIp())) == -1) {
Dis(dis, m, GetIp(), pan.disassembly.bottom - pan.disassembly.top * 2);
@ -692,12 +695,21 @@ static void DrawTerminal(struct Panel *p) {
}
void DrawDisplay(struct Panel *p) {
if (vidya) {
DrawHr(&pan.displayhr, "COLOR GRAPHICS ADAPTER");
DrawCga(p, VirtualSend(m, gc(xmalloc(25 * 80 * 2)), 0xb8000, 25 * 80 * 2));
} else {
DrawHr(&pan.displayhr, "TELETYPEWRITER");
DrawTerminal(p);
switch (vidya) {
case 7:
DrawHr(&pan.displayhr, "MONOCHROME DISPLAY ADAPTER");
DrawMda(p,
VirtualSend(m, gc(xmalloc(25 * 80 * 2)), 0xb0000, 25 * 80 * 2));
break;
case 3:
DrawHr(&pan.displayhr, "COLOR GRAPHICS ADAPTER");
DrawCga(p,
VirtualSend(m, gc(xmalloc(25 * 80 * 2)), 0xb8000, 25 * 80 * 2));
break;
default:
DrawHr(&pan.displayhr, "TELETYPEWRITER");
DrawTerminal(p);
break;
}
}
@ -947,15 +959,17 @@ static void DrawMaps(struct Panel *p) {
static void DrawBreakpoints(struct Panel *p) {
int64_t addr;
char buf[128];
const char *name;
char *s, buf[256];
long i, line, sym;
for (line = 0, i = breakpoints.i; i--;) {
if (breakpoints.p[i].disable) continue;
addr = breakpoints.p[i].addr;
sym = DisFindSym(dis, addr);
name = sym != -1 ? dis->syms.stab + dis->syms.p[sym].name : "UNKNOWN";
snprintf(buf, sizeof(buf), "%p %s", addr, name);
s = buf;
s += sprintf(s, "%p ", addr);
CHECK_LT(Demangle(s, name), buf + ARRAYLEN(buf));
AppendPanel(p, line, buf);
if (sym != -1 && addr != dis->syms.p[sym].addr) {
snprintf(buf, sizeof(buf), "+%#lx", addr - dis->syms.p[sym].addr);
@ -982,8 +996,8 @@ static void DrawTrace(struct Panel *p) {
int i, n;
long sym;
uint8_t *r;
char line[128];
const char *name;
char *s, line[256];
int64_t sp, bp, rp;
rp = m->ip;
bp = Read64(m->bp);
@ -992,7 +1006,9 @@ static void DrawTrace(struct Panel *p) {
rp += Read64(m->cs);
sym = DisFindSym(dis, rp);
name = sym != -1 ? dis->syms.stab + dis->syms.p[sym].name : "UNKNOWN";
snprintf(line, sizeof(line), "%p %p %s", Read64(m->ss) + bp, rp, name);
s = line;
s += sprintf(s, "%p %p ", Read64(m->ss) + bp, rp);
s = Demangle(s, name);
AppendPanel(p, i, line);
if (sym != -1 && rp != dis->syms.p[sym].addr) {
snprintf(line, sizeof(line), "+%#lx", rp - dis->syms.p[sym].addr);
@ -1015,19 +1031,8 @@ static void DrawTrace(struct Panel *p) {
break;
}
sp = bp;
switch (m->mode & 3) {
case XED_MODE_LONG:
bp = Read64(r + 0);
rp = Read64(r + 8);
break;
case XED_MODE_REAL:
case XED_MODE_LEGACY:
bp = Read32(r + 0);
rp = Read32(r + 4);
break;
default:
unreachable;
}
bp = Read64(r + 0);
rp = Read64(r + 8);
}
}
@ -1098,12 +1103,53 @@ static void Redraw(void) {
}
}
static void ReactiveDraw(void) {
if (tuimode) {
m->ip -= m->xedd->length;
SetupDraw();
Redraw();
m->ip += m->xedd->length;
tick = speed;
}
}
static int OnPtyFdClose(int fd) {
return 0;
}
static bool HasPendingInput(int fd) {
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
poll(fds, ARRAYLEN(fds), 0);
return fds[0].revents & (POLLIN | POLLERR);
}
static ssize_t ConsumePtyInput(int fd) {
char *buf;
ssize_t rc;
buf = malloc(PAGESIZE);
pty->conf |= kMachinePtyBlinkcursor;
ReactiveDraw();
rc = read(fd, buf, PAGESIZE);
pty->conf &= ~kMachinePtyBlinkcursor;
ReactiveDraw();
if (rc > 0) MachinePtyWriteInput(pty, buf, rc);
free(buf);
return rc;
}
static ssize_t OnPtyFdRead(int fd, void *data, size_t size) {
return read(fd, data, size);
ssize_t rc;
if (!size) return 0;
if (HasPendingInput(fd)) {
if ((rc = ConsumePtyInput(fd)) <= 0) return rc;
}
while (!(rc = MachinePtyRead(pty, data, size))) {
if ((rc = ConsumePtyInput(fd)) <= 0) return rc;
}
return rc;
}
static ssize_t OnPtyFdWrite(int fd, const void *data, size_t size) {
@ -1115,12 +1161,46 @@ static ssize_t OnPtyFdWrite(int fd, const void *data, size_t size) {
}
}
static int OnPtyFdTiocgwinsz(int fd, struct winsize *ws) {
ws->ws_row = pty->yn;
ws->ws_col = pty->xn;
return 0;
}
static int OnPtyFdTcgets(int fd, struct termios *c) {
memset(c, 0, sizeof(*c));
if (!(pty->conf & kMachinePtyNocanon)) c->c_iflag |= ICANON;
if (!(pty->conf & kMachinePtyNoecho)) c->c_iflag |= ECHO;
if (!(pty->conf & kMachinePtyNoopost)) c->c_oflag |= OPOST;
return 0;
}
static int OnPtyFdTcsets(int fd, uint64_t request, struct termios *c) {
if (c->c_iflag & ICANON) {
pty->conf &= ~kMachinePtyNocanon;
} else {
pty->conf |= kMachinePtyNocanon;
}
if (c->c_iflag & ECHO) {
pty->conf &= ~kMachinePtyNoecho;
} else {
pty->conf |= kMachinePtyNoecho;
}
if (c->c_oflag & OPOST) {
pty->conf &= ~kMachinePtyNoopost;
} else {
pty->conf |= kMachinePtyNoopost;
}
return 0;
}
static int OnPtyFdIoctl(int fd, uint64_t request, void *memory) {
if (request == TIOCGWINSZ) {
struct winsize *ws = memory;
ws->ws_row = pan.display.bottom - pan.display.top;
ws->ws_col = pan.display.right - pan.display.left;
return 0;
return OnPtyFdTiocgwinsz(fd, memory);
} else if (request == TCGETS) {
return OnPtyFdTcgets(fd, memory);
} else if (request == TCSETS || request == TCSETSW || request == TCSETSF) {
return OnPtyFdTcsets(fd, request, memory);
} else {
return einval();
}
@ -1278,9 +1358,59 @@ static void OnDiskService(void) {
}
static void OnVidyaServiceSetMode(void) {
vidya = m->ax[0];
}
static void OnVidyaServiceSetCursor(void) {
static void OnVidyaServiceGetMode(void) {
m->ax[0] = vidya;
m->ax[1] = 80; /* columns */
m->bx[1] = 0; /* page */
}
static void OnVidyaServiceSetCursorPosition(void) {
pty->y = m->dx[1];
pty->x = m->dx[0];
}
static void OnVidyaServiceGetCursorPosition(void) {
m->dx[1] = pty->y;
m->dx[0] = pty->x;
m->cx[1] = 5; /* cursor ▂ scan lines 5..7 of 0..7 */
m->cx[0] = 7 | !!(pty->conf & kMachinePtyNocursor) << 5;
}
static void OnVidyaServiceWriteCharacter(void) {
char buf[12];
int i, n, y, x;
y = pty->y;
x = pty->x;
n = FormatCga(m->bx[0], buf);
n += tpencode(buf + n, 6, kCp437[m->ax[0]], false);
i = Read16(m->cx);
while (i--) MachinePtyWrite(pty, buf, n);
pty->y = y;
pty->x = x;
}
static char16_t VidyaServiceXlatTeletype(uint8_t c) {
switch (c) {
case '\a':
case '\b':
case '\r':
case '\n':
case 0177:
return c;
default:
return kCp437[c];
}
}
static void OnVidyaServiceTeletypeOutput(void) {
int n;
char buf[12];
n = FormatCga(m->bx[0], buf);
n += tpencode(buf + n, 6, VidyaServiceXlatTeletype(m->ax[0]), false);
MachinePtyWrite(pty, buf, n);
}
static void OnVidyaService(void) {
@ -1289,7 +1419,47 @@ static void OnVidyaService(void) {
OnVidyaServiceSetMode();
break;
case 0x02:
OnVidyaServiceSetCursor();
OnVidyaServiceSetCursorPosition();
break;
case 0x03:
OnVidyaServiceGetCursorPosition();
break;
case 0x09:
OnVidyaServiceWriteCharacter();
break;
case 0x0E:
OnVidyaServiceTeletypeOutput();
break;
case 0x0F:
OnVidyaServiceGetMode();
break;
default:
break;
}
}
static void OnKeyboardServiceReadKeyPress(void) {
uint8_t b;
ReactiveDraw();
read(0, &b, 1);
switch (b) {
case 0177:
b = '\b';
break;
case CTRL('C'):
raise(SIGINT);
break;
default:
break;
}
m->ax[0] = b;
m->ax[1] = 0;
}
static void OnKeyboardService(void) {
switch (m->ax[1]) {
case 0x00:
OnKeyboardServiceReadKeyPress();
break;
default:
break;
@ -1356,6 +1526,9 @@ static bool OnHalt(int interrupt) {
case 0x15:
OnInt15h();
return true;
case 0x16:
OnKeyboardService();
return true;
case kMachineSegmentationFault:
OnSegmentationFault();
return false;
@ -1394,11 +1567,19 @@ static void OnPageDown(void) {
}
static void OnUpArrow(void) {
opstart--;
if (action & CONTINUE) {
speed = MIN(0x40000000, MAX(1, speed) << 1);
} else {
--opstart;
}
}
static void OnDownArrow(void) {
opstart++;
if (action & CONTINUE) {
speed >>= 1;
} else {
++opstart;
}
}
static void OnHome(void) {
@ -1422,15 +1603,6 @@ static void OnFeed(void) {
}
static void OnUp(void) {
uint8_t b[8];
int64_t sp, bp, ret;
bp = Read64(m->bp);
sp = Read64(m->sp);
if (bp >= sp) {
VirtualSend(m, b, bp + 8, sizeof(b));
ret = Read64(b);
ScrollOp(&pan.disassembly, GetDisIndex(ret));
}
}
static void OnDown(void) {
@ -1460,7 +1632,7 @@ static void OnFinish(void) {
}
static void OnContinue(void) {
action |= CONTINUE;
action ^= CONTINUE;
action &= ~STEP;
action &= ~NEXT;
action &= ~FINISH;
@ -1495,12 +1667,7 @@ static void OnSseHex(void) {
}
static bool HasPendingKeyboard(void) {
struct pollfd fds[1];
fds[0].fd = ttyfd;
fds[0].events = POLLIN;
fds[0].revents = 0;
poll(fds, ARRAYLEN(fds), 0);
return fds[0].revents & (POLLIN | POLLERR);
return HasPendingInput(ttyfd);
}
static bool IsExecuting(void) {
@ -1700,10 +1867,11 @@ static void Tui(void) {
long op;
ssize_t bp;
int interrupt;
bool interactive;
LOGF("TUI");
TuiSetup();
SetupDraw();
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
ScrollOp(&pan.disassembly, GetDisIndex());
if (!(interrupt = setjmp(m->onhalt))) {
for (;;) {
if (!(action & FAILURE)) {
@ -1719,13 +1887,18 @@ static void Tui(void) {
GetTtySize();
action &= ~WINCHED;
}
SetupDraw();
Redraw();
interactive = ++tick > speed;
if (!(action & CONTINUE) || interactive) {
tick = 0;
GetDisIndex();
SetupDraw();
Redraw();
}
if (action & FAILURE) {
LOGF("TUI FAILURE");
PrintMessageBox(ttyfd, systemfailure, tyn, txn);
ReadKeyboard();
} else if (!IsExecuting() || HasPendingKeyboard()) {
} else if (!IsExecuting() || (interactive && HasPendingKeyboard())) {
ReadKeyboard();
}
if (action & INT) {
@ -1755,7 +1928,7 @@ static void Tui(void) {
break;
}
if (IsExecuting()) {
op = GetDisIndex(m->ip);
op = GetDisIndex();
ScrollOp(&pan.disassembly, op);
VERBOSEF("%s", DisGetLine(dis, m, op));
memcpy(&m[1], &m[0], sizeof(m[0]));
@ -1789,7 +1962,7 @@ static void Tui(void) {
CheckFramePointer();
ops++;
if (!(action & CONTINUE)) {
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
ScrollOp(&pan.disassembly, GetDisIndex());
if ((action & FINISH) && IsRet()) action &= ~FINISH;
if (((action & NEXT) && IsRet()) || (action & FINISH)) {
action &= ~NEXT;
@ -1807,7 +1980,7 @@ static void Tui(void) {
if (OnHalt(interrupt)) {
goto KeepGoing;
}
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
ScrollOp(&pan.disassembly, GetDisIndex());
}
TuiCleanup();
}
@ -1825,7 +1998,6 @@ static void GetOpts(int argc, char *argv[]) {
break;
case 'r':
m->mode = XED_MACHINE_MODE_REAL;
vidya = true;
break;
case 's':
printstats = true;
@ -1834,7 +2006,7 @@ static void GetOpts(int argc, char *argv[]) {
HandleBreakpointFlag(optarg);
break;
case 'H':
g_dis_high = NULL;
memset(&g_high, 0, sizeof(g_high));
break;
case 'v':
++g_loglevel;
@ -1905,14 +2077,14 @@ int main(int argc, char *argv[]) {
m->mode = XED_MACHINE_MODE_LONG_64;
ssewidth = 2; /* 16-bit is best bit */
if (!NoDebug()) showcrashreports();
// OnlyRunOnFirstCpu();
/* OnlyRunOnFirstCpu(); */
if ((colorize = cancolor())) {
high.keyword = 155;
high.reg = 215;
high.literal = 182;
high.label = 221;
high.comment = 112;
g_dis_high = &high;
g_high.keyword = 155;
g_high.reg = 215;
g_high.literal = 182;
g_high.label = 221;
g_high.comment = 112;
g_high.quote = 215;
}
GetOpts(argc, argv);
if (optind == argc) PrintUsage(EX_USAGE, stderr);

View file

@ -47,11 +47,10 @@ uint8_t *GetSegment(struct Machine *m, uint32_t rde, int s) {
uint64_t AddSegment(struct Machine *m, uint32_t rde, uint64_t i, uint8_t s[8]) {
if (!Sego(rde)) {
i += Read64(s);
return i + Read64(s);
} else {
i += Read64(GetSegment(m, rde, Sego(rde) - 1));
return i + Read64(GetSegment(m, rde, Sego(rde) - 1));
}
return i;
}
uint64_t DataSegment(struct Machine *m, uint32_t rde, uint64_t i) {

37
tool/build/lib/breg.c Normal file
View file

@ -0,0 +1,37 @@
/*-*- 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/build/lib/modrm.h"
/**
* Byte register offsets.
*
* for (i = 0; i < 2; ++i) { // rex
* for (j = 0; j < 2; ++j) { // rexb, or rexr
* for (k = 0; k < 8; ++k) { // reg, rm, or srm
* kByteReg[i << 4 | j << 3 | k] =
* i ? (j << 3 | k) * 8 : (k & 0b11) * 8 + ((k & 0b100) >> 2);
* }
* }
* }
*/
const uint8_t kByteReg[32] = {0x00, 0x08, 0x10, 0x18, 0x01, 0x09, 0x11, 0x19,
0x00, 0x08, 0x10, 0x18, 0x01, 0x09, 0x11, 0x19,
0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38,
0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78};

View file

@ -17,9 +17,9 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/tty/tty.h"
#include "libc/alg/arraylist2.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/str/tpencode.h"
@ -58,5 +58,22 @@ void AppendFmt(struct Buffer *b, const char *fmt, ...) {
* Writes buffer until completion, interrupt, or error occurs.
*/
ssize_t WriteBuffer(struct Buffer *b, int fd) {
return ttywrite(fd, b->p, b->i);
char *p;
ssize_t rc;
size_t wrote, n;
p = b->p;
n = b->i;
do {
TryAgain:
if ((rc = write(fd, p, n)) != -1) {
wrote = rc;
p += wrote;
n -= wrote;
} else if (errno == EINTR) {
goto TryAgain;
} else {
return -1;
}
} while (n);
return 0;
}

View file

@ -25,7 +25,6 @@ TOOL_BUILD_LIB_A_OBJS = \
$(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
TOOL_BUILD_LIB_A_DIRECTDEPS = \
DSP_TTY \
LIBC_ALG \
LIBC_BITS \
LIBC_CONV \

View file

@ -17,24 +17,37 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/itoa.h"
#include "libc/macros.h"
#include "libc/str/str.h"
#include "tool/build/lib/buffer.h"
#include "tool/build/lib/cga.h"
static const uint8_t kCgaToAnsi[] = {30, 34, 32, 36, 31, 35, 33, 37,
90, 94, 92, 96, 91, 95, 93, 97};
/* blk blu grn cyn red mag yel wht */
static const uint8_t kCgaToAnsi[16] = {30, 34, 32, 36, 31, 35, 33, 37,
90, 94, 92, 96, 91, 95, 93, 97};
size_t FormatCga(uint8_t bgfg, char buf[hasatleast 11]) {
char *p = buf;
*p++ = '\e';
*p++ = '[';
p += uint64toarray_radix10(kCgaToAnsi[(bgfg & 0xF0) >> 4] + 10, p);
*p++ = ';';
p += uint64toarray_radix10(kCgaToAnsi[bgfg & 0x0F], p);
*p++ = 'm';
*p = '\0';
return p - buf;
}
void DrawCga(struct Panel *p, uint8_t v[25][80][2]) {
char buf[11];
unsigned y, x, n, a;
n = MIN(25, p->bottom - p->top);
for (y = 0; y < n; ++y) {
a = -1;
for (x = 0; x < 80; ++x) {
if (v[y][x][1] != a) {
a = v[y][x][1];
AppendFmt(&p->lines[y], "\e[%d;%dm", kCgaToAnsi[a & 0x0F],
kCgaToAnsi[(a & 0xF0) >> 4] + 10);
AppendData(&p->lines[y], buf, FormatCga((a = v[y][x][1]), buf));
}
AppendWide(&p->lines[y], kCp437[v[y][x][0]]);
}

View file

@ -5,6 +5,7 @@
COSMOPOLITAN_C_START_
void DrawCga(struct Panel *, uint8_t[25][80][2]);
size_t FormatCga(uint8_t, char[hasatleast 11]);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -35,32 +35,32 @@ void OpCpuid(struct Machine *m, uint32_t rde) {
dx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24;
break;
case 1:
cx |= 1 << 0; /* sse3 */
cx |= 0 << 1; /* pclmulqdq */
cx |= 1 << 9; /* ssse3 */
cx |= 1 << 23; /* popcnt */
cx |= 0 << 30; /* rdrnd */
cx |= 0 << 25; /* aes */
dx |= 1 << 0; /* fpu */
dx |= 1 << 4; /* tsc */
dx |= 1 << 6; /* pae */
dx |= 1 << 8; /* cmpxchg8b */
dx |= 1 << 15; /* cmov */
dx |= 1 << 19; /* clflush */
dx |= 1 << 23; /* mmx */
dx |= 1 << 25; /* sse */
dx |= 1 << 26; /* sse2 */
cx |= 1 << 0; // sse3
cx |= 0 << 1; // pclmulqdq
cx |= 1 << 9; // ssse3
cx |= 1 << 23; // popcnt
cx |= 0 << 30; // rdrnd
cx |= 0 << 25; // aes
dx |= 1 << 0; // fpu
dx |= 1 << 4; // tsc
dx |= 1 << 6; // pae
dx |= 1 << 8; // cmpxchg8b
dx |= 1 << 15; // cmov
dx |= 1 << 19; // clflush
dx |= 1 << 23; // mmx
dx |= 1 << 25; // sse
dx |= 1 << 26; // sse2
break;
case 7:
bx |= 1 << 9; /* erms */
bx |= 1 << 9; // erms
break;
case 0x80000001:
cx |= 1 << 0; /* lahf/sahf */
dx |= 1 << 11; /* syscall */
dx |= 1 << 29; /* long mode */
cx |= 1 << 0; // lahf
dx |= 1 << 11; // syscall
dx |= 1 << 29; // long
break;
case 0x80000007:
dx |= 1 << 8; /* invtsc */
dx |= 1 << 8; // invtsc
break;
default:
break;

94
tool/build/lib/demangle.c Normal file
View file

@ -0,0 +1,94 @@
/*-*- 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/hefty/spawn.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "tool/build/lib/demangle.h"
struct CxxFilt {
int pid;
int fds[3];
} g_cxxfilt;
void CloseCxxFilt(void) {
close(g_cxxfilt.fds[0]);
close(g_cxxfilt.fds[1]);
g_cxxfilt.pid = -1;
}
void SpawnCxxFilt(void) {
int pid;
char path[PATH_MAX];
if (commandv("c++filt", path)) {
g_cxxfilt.fds[0] = -1;
g_cxxfilt.fds[1] = -1;
g_cxxfilt.fds[2] = 2;
if ((pid = spawnve(0, g_cxxfilt.fds, path, (char *const[]){"c++filt", NULL},
environ)) != -1) {
atexit(CloseCxxFilt);
}
} else {
pid = -1;
}
g_cxxfilt.pid = pid;
}
char *DemangleCxxFilt(char *p, const char *symbol) {
int n;
char buf[512];
bool iscomplicated;
if (!g_cxxfilt.pid) SpawnCxxFilt();
if (g_cxxfilt.pid == -1) return NULL;
if ((n = strlen(symbol)) >= ARRAYLEN(buf)) return NULL;
memcpy(buf, symbol, n);
buf[n] = '\n';
write(g_cxxfilt.fds[0], buf, n + 1);
n = read(g_cxxfilt.fds[1], buf, ARRAYLEN(buf));
if (n > 1 && buf[n - 1] == '\n') {
if (buf[n - 2] == '\r') --n;
--n;
iscomplicated = memchr(buf, ' ', n) || memchr(buf, '(', n);
if (iscomplicated) *p++ = '"';
p = mempcpy(p, buf, n);
if (iscomplicated) *p++ = '"';
*p = '\0';
return p;
} else {
CloseCxxFilt();
return NULL;
}
}
/**
* Decrypts C++ symbol.
*
* Decoding these takes roughly the same lines of code as an entire
* x86_64 disassembler. That's just for the GNU encoding scheme. So
* what we'll do, is just offload this work to the c++filt program.
*/
char *Demangle(char *p, const char *symbol) {
char *r;
if (startswith(symbol, "_Z")) {
if ((r = DemangleCxxFilt(p, symbol))) return r;
}
return stpcpy(p, symbol);
}

10
tool/build/lib/demangle.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_DEMANGLE_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_DEMANGLE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *Demangle(char *, const char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_DEMANGLE_H_ */

View file

@ -33,7 +33,9 @@
#include "libc/str/tpencode.h"
#include "third_party/xed/x86.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/demangle.h"
#include "tool/build/lib/dis.h"
#include "tool/build/lib/high.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
@ -73,93 +75,99 @@ static char *DisOctets(char *p, const uint8_t *d, size_t n) {
}
static char *DisByte(char *p, const uint8_t *d, size_t n) {
if (g_dis_high) p = DisHigh(p, g_dis_high->keyword);
p = HighStart(p, g_high.keyword);
p = DisColumn(stpcpy(p, ".byte"), p, NAMELEN);
if (g_dis_high) p = DisHigh(p, -1);
p = HighEnd(p);
p = DisOctets(p, d, n);
return p;
}
static char *DisError(struct DisBuilder b, char *p) {
p = DisColumn(DisByte(p, b.xedd->bytes, MIN(15, b.xedd->length)), p, CODELEN);
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
static char *DisError(struct Dis *d, char *p) {
p = DisColumn(DisByte(p, d->xedd->bytes, MIN(15, d->xedd->length)), p,
CODELEN);
p = HighStart(p, g_high.comment);
*p++ = '#';
*p++ = ' ';
p = stpcpy(p, indexdoublenulstring(kXedErrorNames, b.xedd->op.error));
if (g_dis_high) p = DisHigh(p, -1);
p = stpcpy(p, indexdoublenulstring(kXedErrorNames, d->xedd->op.error));
p = HighEnd(p);
*p = '\0';
return p;
}
static char *DisAddr(struct DisBuilder b, char *p) {
if (INT_MIN <= b.addr && b.addr <= INT_MAX) {
return p + uint64toarray_fixed16(b.addr, p, 32);
static char *DisAddr(struct Dis *d, char *p) {
if (INT32_MIN <= d->addr && d->addr <= INT32_MAX) {
return p + uint64toarray_fixed16(d->addr, p, 32);
} else {
return p + uint64toarray_fixed16(b.addr, p, 48);
return p + uint64toarray_fixed16(d->addr, p, 48);
}
}
static char *DisRaw(struct DisBuilder b, char *p) {
static char *DisRaw(struct Dis *d, char *p) {
long i;
for (i = 0; i < PFIXLEN - MIN(PFIXLEN, b.xedd->op.PIVOTOP); ++i) {
for (i = 0; i < PFIXLEN - MIN(PFIXLEN, d->xedd->op.PIVOTOP); ++i) {
*p++ = ' ';
*p++ = ' ';
}
for (i = 0; i < MIN(15, b.xedd->length); ++i) {
if (i == b.xedd->op.PIVOTOP) *p++ = ' ';
*p++ = "0123456789abcdef"[(b.xedd->bytes[i] & 0xf0) >> 4];
*p++ = "0123456789abcdef"[b.xedd->bytes[i] & 0x0f];
for (i = 0; i < MIN(15, d->xedd->length); ++i) {
if (i == d->xedd->op.PIVOTOP) *p++ = ' ';
*p++ = "0123456789abcdef"[(d->xedd->bytes[i] & 0xf0) >> 4];
*p++ = "0123456789abcdef"[d->xedd->bytes[i] & 0x0f];
}
*p = '\0';
return p;
}
static char *DisCode(struct DisBuilder b, char *p) {
static char *DisCode(struct Dis *d, char *p) {
char optspecbuf[128];
if (!b.xedd->op.error) {
return DisInst(b, p, DisSpec(b.xedd, optspecbuf));
if (!d->xedd->op.error) {
return DisInst(d, p, DisSpec(d->xedd, optspecbuf));
} else {
return DisError(b, p);
return DisError(d, p);
}
}
static char *DisLineCode(struct DisBuilder b, char *p) {
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
p = DisColumn(DisRaw(b, p), p, PFIXLEN * 2 + 1 + BYTELEN * 2);
p = DisCode(b, p);
static char *DisLineCode(struct Dis *d, char *p) {
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
p = DisColumn(DisRaw(d, p), p, PFIXLEN * 2 + 1 + BYTELEN * 2);
p = DisCode(d, p);
return p;
}
static char *DisLineData(struct DisBuilder b, char *p, const uint8_t *d,
size_t n) {
static char *DisLineData(struct Dis *d, char *p, const uint8_t *b, size_t n) {
size_t i;
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
p = DisColumn(DisByte(p, d, n), p, 64);
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
p = DisColumn(DisByte(p, b, n), p, 64);
p = HighStart(p, g_high.comment);
*p++ = '#';
*p++ = ' ';
for (i = 0; i < n; ++i) p += tpencode(p, 8, bing(d[i], 0), false);
if (g_dis_high) p = DisHigh(p, -1);
for (i = 0; i < n; ++i) p += tpencode(p, 8, bing(b[i], 0), false);
p = HighEnd(p);
*p = '\0';
return p;
}
static char *DisLabel(struct DisBuilder b, char *p, const char *name) {
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
if (g_dis_high) p = DisHigh(p, g_dis_high->label);
p = stpcpy(p, name);
if (g_dis_high) p = DisHigh(p, -1);
static char *DisLabel(struct Dis *d, char *p, const char *name) {
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
p = HighStart(p, g_high.label);
p = Demangle(p, name);
p = HighEnd(p);
*p++ = ':';
*p = '\0';
return p;
}
long DisFind(struct Dis *d, int64_t addr) {
long i;
for (i = 0; i < d->ops.i; ++i) {
if (addr >= d->ops.p[i].addr &&
addr < d->ops.p[i].addr + d->ops.p[i].size) {
return i;
int l, r, m, i;
l = 0;
r = d->ops.i - 1;
while (l <= r) {
m = (l + r) >> 1;
if (d->ops.p[m].addr < addr) {
l = m + 1;
} else if (d->ops.p[m].addr > addr) {
r = m - 1;
} else {
return m;
}
}
return -1;
@ -181,8 +189,8 @@ static long DisOne(struct Dis *d, struct Machine *m, int64_t addr) {
op.addr = addr;
op.size = 0;
op.active = true;
DisLabel((struct DisBuilder){d, d->xedd, addr}, d->buf,
d->syms.stab + d->syms.p[symbol].name);
d->addr = addr;
DisLabel(d, d->buf, d->syms.stab + d->syms.p[symbol].name);
if (!(op.s = strdup(d->buf))) return -1;
APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op);
}
@ -238,7 +246,8 @@ const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) {
xed_instruction_length_decode(
d->xedd, AccessRam(m, d->ops.p[i].addr, d->ops.p[i].size, r, b, true),
d->ops.p[i].size);
p = DisLineCode((struct DisBuilder){d, d->xedd, d->ops.p[i].addr}, d->buf);
d->addr = d->ops.p[i].addr;
p = DisLineCode(d, d->buf);
CHECK_LT(p - d->buf, sizeof(d->buf));
return d->buf;
}

View file

@ -45,25 +45,10 @@ struct Dis {
} * p;
} edges;
struct XedDecodedInst xedd[1];
uint64_t addr;
char buf[512];
};
struct DisBuilder {
struct Dis *dis;
struct XedDecodedInst *xedd;
int64_t addr;
};
struct DisHigh {
uint8_t keyword;
uint8_t reg;
uint8_t literal;
uint8_t label;
uint8_t comment;
};
extern struct DisHigh *g_dis_high;
long Dis(struct Dis *, struct Machine *, int64_t, int);
long DisFind(struct Dis *, int64_t);
void DisFree(struct Dis *);
@ -74,10 +59,9 @@ long DisFindSym(struct Dis *, int64_t);
long DisFindSymByName(struct Dis *, const char *);
bool DisIsText(struct Dis *, int64_t);
bool DisIsProg(struct Dis *, int64_t);
char *DisInst(struct Dis *, char *, const char *);
char *DisArg(struct Dis *, char *, const char *);
const char *DisSpec(struct XedDecodedInst *, char *);
char *DisInst(struct DisBuilder, char *, const char *);
char *DisArg(struct DisBuilder, char *, const char *);
char *DisHigh(char *, int);
const char *DisGetLine(struct Dis *, struct Machine *, size_t);
COSMOPOLITAN_C_END_

View file

@ -24,23 +24,27 @@
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/str/str.h"
#include "tool/build/lib/demangle.h"
#include "tool/build/lib/dis.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/high.h"
#include "tool/build/lib/modrm.h"
static const char kScale[4][4] = {"", ",2", ",4", ",8"};
static const char kSegName[8][3] = {"es", "cs", "ss", "ds", "fs", "gs"};
static const char kPuttingOnTheRiz[2][4] = {"eiz", "riz"};
static const char kPuttingOnTheRip[2][4] = {"eip", "rip"};
static const char kRiz[2][4] = {"eiz", "riz"};
static const char kRip[2][4] = {"eip", "rip"};
static const char kSka[4][4] = {"", ",2", ",4", ",8"};
static const char kSeg[8][3] = {"es", "cs", "ss", "ds", "fs", "gs"};
static const char kCtl[8][4] = {"cr0", "wut", "cr2", "cr3",
"cr4", "wut", "wut", "wut"};
static const char kRegisterName8[2][2][8][5] = {
static const char kBreg[2][2][8][5] = {
{{"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"},
{"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil"}},
{{"wut", "wut", "wut", "wut", "wut", "wut", "wut", "wut"},
{"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"}},
};
static const char kRegisterName[2][2][2][8][5] = {
static const char kGreg[2][2][2][8][5] = {
{{{"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"},
{"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"}},
{{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"},
@ -51,43 +55,39 @@ static const char kRegisterName[2][2][2][8][5] = {
{"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}},
};
static const char kControlName[8][4] = {
"cr0", "wut", "cr2", "cr3", "cr4", "wut", "wut", "wut",
};
static int64_t RipRelative(struct DisBuilder b, int64_t d) {
return b.addr + b.xedd->length + d;
static int64_t RipRelative(struct Dis *d, int64_t i) {
return d->addr + d->xedd->length + i;
}
static const char *GetAddrReg(struct DisBuilder b, uint32_t rde, uint8_t x,
static const char *GetAddrReg(struct Dis *d, uint32_t rde, uint8_t x,
uint8_t r) {
return kRegisterName[Eamode(rde) == XED_MODE_REAL]
[Eamode(rde) == XED_MODE_LONG][x & 1][r & 7];
return kGreg[Eamode(rde) == XED_MODE_REAL][Eamode(rde) == XED_MODE_LONG]
[x & 1][r & 7];
}
static char *DisRegister(char *p, const char *s) {
if (g_dis_high) p = DisHigh(p, g_dis_high->reg);
p = HighStart(p, g_high.reg);
*p++ = '%';
p = stpcpy(p, s);
if (g_dis_high) p = DisHigh(p, -1);
p = HighEnd(p);
return p;
}
static char *DisComment(char *p, const char *s) {
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
p = HighStart(p, g_high.comment);
p = stpcpy(p, s);
if (g_dis_high) p = DisHigh(p, -1);
p = HighEnd(p);
return p;
}
static char *DisRegisterByte(struct DisBuilder b, uint32_t rde, char *p, bool g,
static char *DisRegisterByte(struct Dis *d, uint32_t rde, char *p, bool g,
int r) {
return DisRegister(p, kRegisterName8[g][Rex(rde)][r]);
return DisRegister(p, kBreg[g][Rex(rde)][r]);
}
static char *DisRegisterWord(struct DisBuilder b, uint32_t rde, char *p, bool g,
static char *DisRegisterWord(struct Dis *d, uint32_t rde, char *p, bool g,
int r) {
return DisRegister(p, kRegisterName[Osz(rde)][Rexw(rde)][g][r]);
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][g][r]);
}
static char *DisInt(char *p, int64_t x) {
@ -106,14 +106,14 @@ static char *DisInt(char *p, int64_t x) {
return p;
}
static char *DisSym(struct DisBuilder b, char *p, int64_t addr) {
static char *DisSym(struct Dis *d, char *p, int64_t addr) {
long sym;
int64_t addend;
const char *name;
if ((sym = DisFindSym(b.dis, addr)) != -1 && b.dis->syms.p[sym].name) {
addend = addr - b.dis->syms.p[sym].addr;
name = b.dis->syms.stab + b.dis->syms.p[sym].name;
p = stpcpy(p, name);
if ((sym = DisFindSym(d, addr)) != -1 && d->syms.p[sym].name) {
addend = addr - d->syms.p[sym].addr;
name = d->syms.stab + d->syms.p[sym].name;
p = Demangle(p, name);
if (addend) {
*p++ = '+';
p = DisInt(p, addend);
@ -124,79 +124,69 @@ static char *DisSym(struct DisBuilder b, char *p, int64_t addr) {
}
}
static char *DisSymLiteral(struct DisBuilder b, char *p, uint64_t x) {
static char *DisSymLiteral(struct Dis *d, char *p, uint64_t x) {
*p++ = '$';
if (g_dis_high) p = DisHigh(p, g_dis_high->literal);
p = DisSym(b, p, x);
if (g_dis_high) p = DisHigh(p, -1);
p = HighStart(p, g_high.literal);
p = DisSym(d, p, x);
p = HighEnd(p);
return p;
}
static char *DisXmm(struct DisBuilder b, uint32_t rde, char *p, const char *s,
int reg) {
if (g_dis_high) p = DisHigh(p, g_dis_high->reg);
*p++ = '%';
p = stpcpy(p, s);
p += uint64toarray_radix10(Rexr(rde) << 3 | reg, p);
if (g_dis_high) p = DisHigh(p, -1);
return p;
static char *DisGvqp(struct Dis *d, uint32_t rde, char *p) {
return DisRegisterWord(d, rde, p, Rexr(rde), ModrmReg(rde));
}
static char *DisGvqp(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegisterWord(b, rde, p, Rexr(rde), ModrmReg(rde));
static char *DisGdqp(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kGreg[0][Rexw(rde)][Rexr(rde)][ModrmReg(rde)]);
}
static char *DisGdqp(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegister(p, kRegisterName[0][Rexw(rde)][Rexr(rde)][ModrmReg(rde)]);
static char *DisGb(struct Dis *d, uint32_t rde, char *p) {
return DisRegisterByte(d, rde, p, Rexr(rde), ModrmReg(rde));
}
static char *DisGb(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegisterByte(b, rde, p, Rexr(rde), ModrmReg(rde));
}
static char *DisSego(struct DisBuilder b, uint32_t rde, char *p) {
static char *DisSego(struct Dis *d, uint32_t rde, char *p) {
int seg;
seg = Sego(rde) ? Sego(rde) : b.xedd->op.hint;
seg = Sego(rde) ? Sego(rde) : d->xedd->op.hint;
if (seg) {
p = DisRegister(p, kSegName[seg - 1]);
p = DisRegister(p, kSeg[seg - 1]);
*p++ = ':';
}
return p;
}
static char *DisM(struct DisBuilder b, uint32_t rde, char *p) {
static char *DisM(struct Dis *d, uint32_t rde, char *p) {
int64_t disp;
const char *base, *index, *scale;
p = DisSego(b, rde, p);
p = DisSego(d, rde, p);
base = index = scale = NULL;
if (ModrmMod(rde) == 0b01 || ModrmMod(rde) == 0b10 || IsRipRelative(rde) ||
(Eamode(rde) == XED_MODE_REAL && ModrmRm(rde) == 6 && !ModrmMod(rde)) ||
(ModrmMod(rde) == 0b00 && ModrmRm(rde) == 0b100 &&
SibBase(b.xedd) == 0b101)) {
disp = b.xedd->op.disp;
if (IsRipRelative(rde)) disp = RipRelative(b, disp);
p = DisSym(b, p, disp);
SibBase(d->xedd) == 0b101)) {
disp = d->xedd->op.disp;
if (IsRipRelative(rde)) disp = RipRelative(d, disp);
p = DisSym(d, p, disp);
}
if (Eamode(rde) != XED_MODE_REAL) {
if (!SibExists(rde)) {
DCHECK(!b.xedd->op.has_sib);
DCHECK(!d->xedd->op.has_sib);
if (IsRipRelative(rde)) {
if (Mode(rde) == XED_MODE_LONG) {
base = kPuttingOnTheRip[Eamode(rde) == XED_MODE_LONG];
base = kRip[Eamode(rde) == XED_MODE_LONG];
}
} else {
base = GetAddrReg(b, rde, Rexb(rde), ModrmRm(rde));
base = GetAddrReg(d, rde, Rexb(rde), ModrmRm(rde));
}
} else if (!SibIsAbsolute(b.xedd, rde)) {
if (SibHasBase(b.xedd, rde)) {
base = GetAddrReg(b, rde, Rexb(rde), SibBase(b.xedd));
} else if (!SibIsAbsolute(d->xedd, rde)) {
if (SibHasBase(d->xedd, rde)) {
base = GetAddrReg(d, rde, Rexb(rde), SibBase(d->xedd));
}
if (SibHasIndex(b.xedd)) {
index = GetAddrReg(b, rde, Rexx(b.xedd), SibIndex(b.xedd));
} else if (b.xedd->op.scale) {
index = kPuttingOnTheRiz[Eamode(rde) == XED_MODE_LONG];
if (SibHasIndex(d->xedd)) {
index = GetAddrReg(d, rde, Rexx(d->xedd), SibIndex(d->xedd));
} else if (d->xedd->op.scale) {
index = kRiz[Eamode(rde) == XED_MODE_LONG];
}
scale = kScale[b.xedd->op.scale];
scale = kSka[d->xedd->op.scale];
}
} else {
switch (ModrmRm(rde)) {
@ -250,206 +240,235 @@ static char *DisM(struct DisBuilder b, uint32_t rde, char *p) {
return p;
}
static char *DisEb(struct DisBuilder b, uint32_t rde, char *p) {
static char *DisRegMem(struct Dis *d, uint32_t rde, char *p,
char *f(struct Dis *, uint32_t, char *)) {
if (IsModrmRegister(rde)) {
return DisRegisterByte(b, rde, p, Rexb(rde), ModrmRm(rde));
return f(d, rde, p);
} else {
return DisM(b, rde, p);
return DisM(d, rde, p);
}
}
static char *DisEvqp(struct DisBuilder b, uint32_t rde, char *p) {
static noinline char *DisE(struct Dis *d, uint32_t rde, char *p,
char *f(struct Dis *, uint32_t, char *, bool, int)) {
if (IsModrmRegister(rde)) {
return DisRegisterWord(b, rde, p, Rexb(rde), ModrmRm(rde));
return f(d, rde, p, Rexb(rde), ModrmRm(rde));
} else {
return DisM(b, rde, p);
return DisM(d, rde, p);
}
}
static char *DisEdqp(struct DisBuilder b, uint32_t rde, char *p) {
if (IsModrmRegister(rde)) {
return DisRegister(p, kRegisterName[0][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]);
} else {
return DisM(b, rde, p);
}
static char *DisEb(struct Dis *d, uint32_t rde, char *p) {
return DisE(d, rde, p, DisRegisterByte);
}
static char *DisEv(struct DisBuilder b, uint32_t rde, char *p) {
const char *s;
if (IsModrmRegister(rde)) {
return DisRegister(p, kRegisterName[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]);
} else {
return DisM(b, rde, p);
}
static char *DisEvqp(struct Dis *d, uint32_t rde, char *p) {
return DisE(d, rde, p, DisRegisterWord);
}
static char *DisGvq(struct DisBuilder b, uint32_t rde, char *p, int r) {
static char *DisEdqpReg(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kGreg[0][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]);
}
static char *DisEdqp(struct Dis *d, uint32_t rde, char *p) {
return DisRegMem(d, rde, p, DisEdqpReg);
}
static char *DisEvReg(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]);
}
static char *DisEv(struct Dis *d, uint32_t rde, char *p) {
return DisRegMem(d, rde, p, DisEvReg);
}
static char *DisGvq(struct Dis *d, uint32_t rde, char *p, int r) {
const char *s;
if (Mode(rde) == XED_MODE_LONG) {
s = kRegisterName[Osz(rde)][!Osz(rde)][Rexb(rde)][r];
s = kGreg[Osz(rde)][!Osz(rde)][Rexb(rde)][r];
} else {
s = kRegisterName[Osz(rde)][0][Rexb(rde)][r];
s = kGreg[Osz(rde)][0][Rexb(rde)][r];
}
return DisRegister(p, s);
}
static char *DisZvq(struct DisBuilder b, uint32_t rde, char *p) {
return DisGvq(b, rde, p, ModrmSrm(rde));
static char *DisZvq(struct Dis *d, uint32_t rde, char *p) {
return DisGvq(d, rde, p, ModrmSrm(rde));
}
static char *DisEvq(struct DisBuilder b, uint32_t rde, char *p) {
if (IsModrmRegister(rde)) {
return DisGvq(b, rde, p, ModrmRm(rde));
static char *DisEvqReg(struct Dis *d, uint32_t rde, char *p) {
return DisGvq(d, rde, p, ModrmRm(rde));
}
static char *DisEvq(struct Dis *d, uint32_t rde, char *p) {
return DisRegMem(d, rde, p, DisEvqReg);
}
static char *DisEdReg(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kGreg[0][0][Rexb(rde)][ModrmRm(rde)]);
}
static char *DisEd(struct Dis *d, uint32_t rde, char *p) {
return DisRegMem(d, rde, p, DisEdReg);
}
static char *DisEqReg(struct Dis *d, uint32_t rde, char *p) {
const char *r;
if (Mode(rde) == XED_MODE_LONG) {
r = kGreg[0][1][Rexb(rde)][ModrmRm(rde)];
} else {
return DisM(b, rde, p);
r = kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)];
}
return DisRegister(p, r);
}
static char *DisEd(struct DisBuilder b, uint32_t rde, char *p) {
if (IsModrmRegister(rde)) {
return DisRegister(p, kRegisterName[0][0][Rexb(rde)][ModrmRm(rde)]);
} else {
return DisM(b, rde, p);
}
static char *DisEq(struct Dis *d, uint32_t rde, char *p) {
return DisRegMem(d, rde, p, DisEqReg);
}
static char *DisEq(struct DisBuilder b, uint32_t rde, char *p) {
if (IsModrmRegister(rde)) {
return DisRegister(p, kRegisterName[0][1][Rexb(rde)][ModrmRm(rde)]);
} else {
return DisM(b, rde, p);
}
static char *DisZvqp(struct Dis *d, uint32_t rde, char *p) {
return DisRegisterWord(d, rde, p, Rexb(rde), ModrmSrm(rde));
}
static char *DisZvqp(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegisterWord(b, rde, p, Rexb(rde), ModrmSrm(rde));
static char *DisZb(struct Dis *d, uint32_t rde, char *p) {
return DisRegisterByte(d, rde, p, Rexb(rde), ModrmSrm(rde));
}
static char *DisZb(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegisterByte(b, rde, p, Rexb(rde), ModrmSrm(rde));
static char *DisEax(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kGreg[Osz(rde)][0][0][0]);
}
static char *DisEax(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegister(p, kRegisterName[Osz(rde)][0][0][0]);
static char *DisRax(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][0][0]);
}
static char *DisRax(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegister(p, kRegisterName[Osz(rde)][Rexw(rde)][0][0]);
static char *DisRdx(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][0][2]);
}
static char *DisRdx(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegister(p, kRegisterName[Osz(rde)][Rexw(rde)][0][2]);
static char *DisCd(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kCtl[ModrmReg(rde)]);
}
static char *DisCd(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegister(p, kControlName[ModrmReg(rde)]);
static char *DisHd(struct Dis *d, uint32_t rde, char *p) {
return DisRegister(p, kGreg[0][Mode(rde) == XED_MODE_LONG][0][ModrmRm(rde)]);
}
static char *DisHd(struct DisBuilder b, uint32_t rde, char *p) {
return DisRegister(
p, kRegisterName[0][Mode(rde) == XED_MODE_LONG][0][ModrmRm(rde)]);
static char *DisImm(struct Dis *d, uint32_t rde, char *p) {
return DisSymLiteral(d, p, d->xedd->op.uimm0);
}
static char *DisImm(struct DisBuilder b, uint32_t rde, char *p) {
return DisSymLiteral(b, p, b.xedd->op.uimm0);
static char *DisRvds(struct Dis *d, uint32_t rde, char *p) {
return DisSymLiteral(d, p, d->xedd->op.disp);
}
static char *DisRvds(struct DisBuilder b, uint32_t rde, char *p) {
return DisSymLiteral(b, p, b.xedd->op.disp);
}
static char *DisKvds(struct DisBuilder b, uint32_t rde, char *p) {
static char *DisKpvds(struct Dis *d, uint32_t rde, char *p, uint64_t x) {
*p++ = '$';
if (g_dis_high) p = DisHigh(p, g_dis_high->literal);
p = DisInt(p, b.xedd->op.uimm0);
if (g_dis_high) p = DisHigh(p, -1);
p = HighStart(p, g_high.literal);
p = DisInt(p, x);
p = HighEnd(p);
return p;
}
static char *DisOne(struct DisBuilder b, uint32_t rde, char *p) {
static char *DisKvds(struct Dis *d, uint32_t rde, char *p) {
return DisKpvds(d, rde, p, d->xedd->op.uimm0);
}
static char *DisPvds(struct Dis *d, uint32_t rde, char *p) {
return DisKpvds(d, rde, p,
d->xedd->op.disp & (Osz(rde) ? 0xffff : 0xffffffff));
}
static char *DisOne(struct Dis *d, uint32_t rde, char *p) {
*p++ = '$';
if (g_dis_high) p = DisHigh(p, g_dis_high->literal);
p = HighStart(p, g_high.literal);
p = stpcpy(p, "1");
if (g_dis_high) p = DisHigh(p, -1);
p = HighEnd(p);
return p;
}
static char *DisJbs(struct DisBuilder b, uint32_t rde, char *p) {
if (b.xedd->op.disp > 0) *p++ = '+';
p += int64toarray_radix10(b.xedd->op.disp, p);
static char *DisJbs(struct Dis *d, uint32_t rde, char *p) {
if (d->xedd->op.disp > 0) *p++ = '+';
p += int64toarray_radix10(d->xedd->op.disp, p);
return p;
}
static char *DisJb(struct DisBuilder b, uint32_t rde, char *p) {
if (b.xedd->op.disp > 0) *p++ = '+';
p += uint64toarray_radix10(b.xedd->op.disp & 0xff, p);
static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
if (d->xedd->op.disp > 0) *p++ = '+';
p += uint64toarray_radix10(d->xedd->op.disp & 0xff, p);
return p;
}
static char *DisJvds(struct DisBuilder b, uint32_t rde, char *p) {
return DisSym(b, p, RipRelative(b, b.xedd->op.disp));
static char *DisJvds(struct Dis *d, uint32_t rde, char *p) {
return DisSym(d, p, RipRelative(d, d->xedd->op.disp));
}
static char *DisAbs(struct DisBuilder b, uint32_t rde, char *p) {
return DisSym(b, p, b.xedd->op.disp);
static char *DisAbs(struct Dis *d, uint32_t rde, char *p) {
return DisSym(d, p, d->xedd->op.disp);
}
static char *DisSw(struct DisBuilder b, uint32_t rde, char *p) {
if (kSegName[ModrmReg(rde)][0]) p = DisRegister(p, kSegName[ModrmReg(rde)]);
static char *DisSw(struct Dis *d, uint32_t rde, char *p) {
if (kSeg[ModrmReg(rde)][0]) p = DisRegister(p, kSeg[ModrmReg(rde)]);
return p;
}
static char *DisSpecialAddr(struct DisBuilder b, uint32_t rde, char *p, int r) {
static char *DisSpecialAddr(struct Dis *d, uint32_t rde, char *p, int r) {
*p++ = '(';
p = DisRegister(p, GetAddrReg(b, rde, 0, r));
p = DisRegister(p, GetAddrReg(d, rde, 0, r));
*p++ = ')';
*p = '\0';
return p;
}
static char *DisY(struct DisBuilder b, uint32_t rde, char *p) {
return DisSpecialAddr(b, rde, p, 7); // es:di
static char *DisY(struct Dis *d, uint32_t rde, char *p) {
return DisSpecialAddr(d, rde, p, 7); // es:di
}
static char *DisX(struct DisBuilder b, uint32_t rde, char *p) {
DisSego(b, rde, p);
return DisSpecialAddr(b, rde, p, 6); // ds:si
static char *DisX(struct Dis *d, uint32_t rde, char *p) {
DisSego(d, rde, p);
return DisSpecialAddr(d, rde, p, 6); // ds:si
}
static char *DisBBb(struct DisBuilder b, uint32_t rde, char *p) {
DisSego(b, rde, p);
return DisSpecialAddr(b, rde, p, 3); // ds:bx
static char *DisBBb(struct Dis *d, uint32_t rde, char *p) {
DisSego(d, rde, p);
return DisSpecialAddr(d, rde, p, 3); // ds:bx
}
static char *DisNq(struct DisBuilder b, uint32_t rde, char *p) {
return DisXmm(b, rde, p, "mm", ModrmRm(rde));
static char *DisXmm(struct Dis *d, uint32_t rde, char *p, const char *s,
int reg) {
p = HighStart(p, g_high.reg);
*p++ = '%';
p = stpcpy(p, s);
p += uint64toarray_radix10(reg, p);
p = HighEnd(p);
return p;
}
static char *DisUq(struct DisBuilder b, uint32_t rde, char *p) {
return DisXmm(b, rde, p, "mm", ModrmRm(rde));
static char *DisNq(struct Dis *d, uint32_t rde, char *p) {
return DisXmm(d, rde, p, "mm", ModrmRm(rde));
}
static char *DisPq(struct DisBuilder b, uint32_t rde, char *p) {
return DisXmm(b, rde, p, "mm", ModrmReg(rde));
static char *DisPq(struct Dis *d, uint32_t rde, char *p) {
return DisXmm(d, rde, p, "mm", ModrmReg(rde));
}
static char *DisUdq(struct DisBuilder b, uint32_t rde, char *p) {
return DisXmm(b, rde, p, "xmm", ModrmRm(rde));
static char *DisUq(struct Dis *d, uint32_t rde, char *p) {
return DisXmm(d, rde, p, "xmm", RexbRm(rde));
}
static char *DisVdq(struct DisBuilder b, uint32_t rde, char *p) {
return DisXmm(b, rde, p, "xmm", ModrmReg(rde));
static char *DisUdq(struct Dis *d, uint32_t rde, char *p) {
return DisXmm(d, rde, p, "xmm", RexbRm(rde));
}
static char *DisQq(struct DisBuilder b, uint32_t rde, char *p) {
if (IsModrmRegister(rde)) {
return DisNq(b, rde, p);
} else {
return DisM(b, rde, p);
}
static char *DisVdq(struct Dis *d, uint32_t rde, char *p) {
return DisXmm(d, rde, p, "xmm", RexrReg(rde));
}
static char *DisEst(struct DisBuilder b, uint32_t rde, char *p) {
static char *DisQq(struct Dis *d, uint32_t rde, char *p) {
return DisRegMem(d, rde, p, DisNq);
}
static char *DisEst(struct Dis *d, uint32_t rde, char *p) {
p = DisRegister(p, "st");
if (ModrmRm(rde) != 0) {
*p++ = '(';
@ -460,29 +479,21 @@ static char *DisEst(struct DisBuilder b, uint32_t rde, char *p) {
return p;
}
static char *DisEst1(struct DisBuilder b, uint32_t rde, char *p) {
static char *DisEst1(struct Dis *d, uint32_t rde, char *p) {
if (ModrmRm(rde) != 1) {
p = DisEst(b, rde, p);
p = DisEst(d, rde, p);
} else {
*p = '\0';
}
return p;
}
static char *DisEssr(struct DisBuilder b, uint32_t rde, char *p) {
if (IsModrmRegister(rde)) {
return DisEst(b, rde, p);
} else {
return DisM(b, rde, p);
}
static char *DisEssr(struct Dis *d, uint32_t rde, char *p) {
return DisRegMem(d, rde, p, DisEst);
}
static char *DisWps(struct DisBuilder b, uint32_t rde, char *p) {
if (IsModrmRegister(rde)) {
return DisUdq(b, rde, p);
} else {
return DisM(b, rde, p);
}
static char *DisWps(struct Dis *d, uint32_t rde, char *p) {
return DisRegMem(d, rde, p, DisUdq);
}
#define DisEdr DisM
@ -537,7 +548,7 @@ static char *DisWps(struct DisBuilder b, uint32_t rde, char *p) {
static const struct DisArg {
char s[8];
char *(*f)(struct DisBuilder, uint32_t, char *);
char *(*f)(struct Dis *, uint32_t, char *);
} kDisArgs[] = /* <sorted> */ {
{"$1", DisOne}, //
{"%Cd", DisCd}, //
@ -610,6 +621,7 @@ static const struct DisArg {
{"Mwi", DisMwi}, //
{"Ob", DisOb}, //
{"Ovqp", DisOvqp}, //
{"Pvds", DisPvds}, //
{"Qpi", DisQpi}, //
{"Qq", DisQq}, //
{"Rvds", DisRvds}, //
@ -635,7 +647,7 @@ static int CompareString8(const char a[8], const char b[8]) {
return x > y ? 1 : x < y ? -1 : 0;
}
char *DisArg(struct DisBuilder b, char *p, const char *s) {
char *DisArg(struct Dis *d, char *p, const char *s) {
char key[8];
int c, m, l, r;
l = 0;
@ -649,7 +661,7 @@ char *DisArg(struct DisBuilder b, char *p, const char *s) {
} else if (c > 0) {
r = m - 1;
} else {
return kDisArgs[m].f(b, b.xedd->op.rde, p);
return kDisArgs[m].f(d, d->xedd->op.rde, p);
}
}
if (*s == '%') {

View file

@ -115,31 +115,33 @@ bool DisIsText(struct Dis *d, int64_t addr) {
long DisFindSym(struct Dis *d, int64_t addr) {
size_t i, l, r, m, n;
if (DisIsProg(d, addr)) {
l = 0;
r = d->syms.i;
while (l < r) {
m = (l + r) >> 1;
if (d->syms.p[m].addr < addr) {
l = m + 1;
} else {
r = m;
if (d->syms.p) {
if (DisIsProg(d, addr)) {
l = 0;
r = d->syms.i;
while (l < r) {
m = (l + r) >> 1;
if (d->syms.p[m].addr < addr) {
l = m + 1;
} else {
r = m;
}
}
}
if (d->syms.p[l].addr == addr) {
return l;
}
l = MAX(0, (long)l - 10);
for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) {
if (addr >= d->syms.p[i].addr &&
addr < d->syms.p[i].addr + d->syms.p[i].size) {
return i;
if (d->syms.p[l].addr == addr) {
return l;
}
}
for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) {
if (addr >= d->syms.p[i].addr &&
(i + 1 == d->syms.i || addr < d->syms.p[i + 1].addr)) {
return i;
l = MAX(0, (long)l - 10);
for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) {
if (addr >= d->syms.p[i].addr &&
addr < d->syms.p[i].addr + d->syms.p[i].size) {
return i;
}
}
for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) {
if (addr >= d->syms.p[i].addr &&
(i + 1 == d->syms.i || addr < d->syms.p[i + 1].addr)) {
return i;
}
}
}
}

View file

@ -21,6 +21,7 @@
#include "libc/nexgen32e/tinystrcmp.h"
#include "libc/str/str.h"
#include "tool/build/lib/dis.h"
#include "tool/build/lib/high.h"
#include "tool/build/lib/modrm.h"
static const char kJcxz[3][6] = {"jcxz", "jecxz", "jrcxz"};
@ -28,43 +29,45 @@ static const char kAluOp[8][4] = {"add", "or", "adc", "sbb",
"and", "sub", "xor", "cmp"};
static const char kBitOp[8][4] = {"rol", "ror", "rcl", "rcr",
"shl", "shr", "sal", "sar"};
static const char kCc[16][3] = {"o", "no", "b", "ae", "e", "ne", "be", "a",
"s", "ns", "p", "np", "l", "ge", "le", "g"};
static bool IsProbablyByteOp(struct XedDecodedInst *x) {
return !(x->op.opcode & 1);
}
static int IsRepOpcode(struct DisBuilder b) {
switch (b.xedd->op.opcode & ~1) {
case 0x6C: /* INS */
static int IsRepOpcode(struct Dis *d) {
switch (d->xedd->op.opcode & ~1) {
case 0x6C: // INS
return 1;
case 0x6E: /* OUTS */
case 0x6E: // OUTS
return 1;
case 0xA4: /* MOVS */
case 0xA4: // MOVS
return 1;
case 0xAA: /* STOS */
case 0xAA: // STOS
return 1;
case 0xAC: /* LODS */
case 0xAC: // LODS
return 1;
case 0xA6: /* CMPS */
case 0xA6: // CMPS
return 2;
case 0xAE: /* SCAS */
case 0xAE: // SCAS
return 2;
default:
return 0;
}
}
static char *DisRepPrefix(struct DisBuilder b, char *p) {
static char *DisRepPrefix(struct Dis *d, char *p) {
const char *s;
if (Rep(b.xedd->op.rde) && b.xedd->op.map == XED_ILD_MAP0) {
switch (IsRepOpcode(b)) {
if (Rep(d->xedd->op.rde) && d->xedd->op.map == XED_ILD_MAP0) {
switch (IsRepOpcode(d)) {
case 0:
break;
case 1:
p = stpcpy(p, "rep ");
break;
case 2:
p = stpcpy(p, Rep(b.xedd->op.rde) == 2 ? "repnz " : "repz ");
p = stpcpy(p, Rep(d->xedd->op.rde) == 2 ? "repnz " : "repz ");
break;
default:
break;
@ -73,8 +76,8 @@ static char *DisRepPrefix(struct DisBuilder b, char *p) {
return p;
}
static char *DisBranchTaken(struct DisBuilder b, char *p) {
switch (b.xedd->op.hint) {
static char *DisBranchTaken(struct Dis *d, char *p) {
switch (d->xedd->op.hint) {
case XED_HINT_NTAKEN:
return stpcpy(p, ",pn");
case XED_HINT_TAKEN:
@ -84,24 +87,26 @@ static char *DisBranchTaken(struct DisBuilder b, char *p) {
}
}
static char *DisName(struct DisBuilder b, char *bp, const char *name,
static char *DisName(struct Dis *d, char *bp, const char *name,
bool ambiguous) {
char *p, *np;
uint32_t rde;
bool notbyte, notlong, wantsuffix, wantsuffixsd;
p = bp;
rde = b.xedd->op.rde;
if (b.xedd->op.lock) p = stpcpy(p, "lock ");
p = DisRepPrefix(b, p);
rde = d->xedd->op.rde;
if (d->xedd->op.lock) p = stpcpy(p, "lock ");
p = DisRepPrefix(d, p);
if (tinystrcmp(name, "BIT") == 0) {
p = stpcpy(p, kBitOp[ModrmReg(rde)]);
} else if (tinystrcmp(name, "nop") == 0 && d->xedd->op.rep) {
p = stpcpy(p, "pause");
} else if (tinystrcmp(name, "CALL") == 0) {
p = stpcpy(p, "call");
} else if (tinystrcmp(name, "JMP") == 0) {
p = stpcpy(p, "jmp");
} else if (tinystrcmp(name, "jcxz") == 0) {
p = stpcpy(p, kJcxz[Eamode(rde)]);
p = DisBranchTaken(b, p);
p = DisBranchTaken(d, p);
} else if (tinystrcmp(name, "loop") == 0 || tinystrcmp(name, "loope") == 0 ||
tinystrcmp(name, "loopne") == 0) {
p = stpcpy(p, name);
@ -109,7 +114,7 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
*p++ = "wl"[Eamode(rde)];
*p = '\0';
}
p = DisBranchTaken(b, p);
p = DisBranchTaken(d, p);
} else if (tinystrcmp(name, "cwtl") == 0) {
if (Osz(rde)) name = "cbtw";
if (Rexw(rde)) name = "cltq";
@ -127,10 +132,15 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
*p++ = *np;
}
if (tinystrcmp(name, "ALU") == 0) {
p = stpcpy(p, kAluOp[(d->xedd->op.opcode & 070) >> 3]);
} else if (tinystrcmp(name, "ALU2") == 0) {
p = stpcpy(p, kAluOp[ModrmReg(rde)]);
} else if (tinystrcmp(np, "WLQ") == 0) {
notbyte = true;
wantsuffix = true;
} else if (tinystrcmp(np, "CC") == 0) {
p = stpcpy(p, kCc[d->xedd->op.opcode & 15]);
p = DisBranchTaken(d, p);
} else if (tinystrcmp(np, "WQ") == 0) {
notbyte = true;
notlong = Eamode(rde) != XED_MODE_REAL;
@ -143,8 +153,6 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
wantsuffixsd = true;
} else if (tinystrcmp(np, "ABS") == 0) {
if (Rexw(rde)) p = stpcpy(p, "abs");
} else if (tinystrcmp(np, "BT") == 0) {
p = DisBranchTaken(b, p);
}
if (wantsuffixsd) {
if (Osz(rde)) {
@ -155,12 +163,12 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
} else if (wantsuffix || (ambiguous && !startswith(name, "f") &&
!startswith(name, "set"))) {
if (Osz(rde)) {
if (Eamode(rde) != XED_MODE_REAL) {
if (Mode(rde) != XED_MODE_REAL) {
*p++ = 'w';
}
} else if (Rexw(rde)) {
*p++ = 'q';
} else if (ambiguous && !notbyte && IsProbablyByteOp(b.xedd)) {
} else if (ambiguous && !notbyte && IsProbablyByteOp(d->xedd)) {
*p++ = 'b';
} else if (!notlong) {
*p++ = 'l';
@ -177,28 +185,28 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
* Disassembles instruction based on string spec.
* @see DisSpec()
*/
char *DisInst(struct DisBuilder b, char *p, const char *spec) {
char *DisInst(struct Dis *d, char *p, const char *spec) {
long i, n;
char sbuf[256];
char args[4][128];
char sbuf[300];
char args[4][300];
char *s, *name, *state;
bool hasarg, hasmodrm, hasregister, hasmemory;
CHECK_EQ(0, (int)b.xedd->op.error);
CHECK_EQ(0, (int)d->xedd->op.error);
DCHECK_LT(strlen(spec), 128);
hasarg = false;
hasmodrm = b.xedd->op.has_modrm;
hasmemory = hasmodrm && !IsModrmRegister(b.xedd->op.rde);
hasregister = hasmodrm && IsModrmRegister(b.xedd->op.rde);
hasmodrm = d->xedd->op.has_modrm;
hasmemory = hasmodrm && !IsModrmRegister(d->xedd->op.rde);
hasregister = hasmodrm && IsModrmRegister(d->xedd->op.rde);
name = strtok_r(strcpy(sbuf, spec), " ", &state);
for (n = 0; (s = strtok_r(NULL, " ", &state)); ++n) {
hasarg = true;
hasregister |= *s == '%';
hasmemory |= *s == 'O';
CHECK_LT(DisArg(b, args[n], s) - args[n], sizeof(args[n]));
CHECK_LT(DisArg(d, args[n], s) - args[n], sizeof(args[n]));
}
if (g_dis_high) p = DisHigh(p, g_dis_high->keyword);
p = DisName(b, p, name, hasarg && !hasregister && hasmemory);
if (g_dis_high) p = DisHigh(p, -1);
p = HighStart(p, g_high.keyword);
p = DisName(d, p, name, hasarg && !hasregister && hasmemory);
p = HighEnd(p);
for (i = 0; i < n; ++i) {
if (i && args[n - i][0]) {
*p++ = ',';

View file

@ -36,12 +36,6 @@ static const char kFpuName[][8][8] = {
{"fneni", "fndisi", "fnclex", "fninit", "fnsetpm"},
};
char *DisOpFpu0(struct XedDecodedInst *x, int group) {
const char *s;
s = kFpuName[group][ModrmRm(x->op.rde)];
return *s ? s : UNKNOWN;
}
char *DisOpFpu1(struct XedDecodedInst *x, char *p, const char *extra) {
stpcpy(stpcpy(p, kFpuName[0][ModrmReg(x->op.rde)]), extra);
return p;
@ -88,68 +82,88 @@ char *DisOpVpsWpsVssWssVpdWpdVsdWsd(struct XedDecodedInst *x, char *p,
return p;
}
const char *DisSpecFpu0(struct XedDecodedInst *x, int group) {
const char *s;
s = kFpuName[group][ModrmRm(x->op.rde)];
return *s ? s : UNKNOWN;
}
const char *DisSpecRegMem(struct XedDecodedInst *x, const char *a,
const char *b) {
if (IsModrmRegister(x->op.rde)) {
return a;
} else {
return b;
}
}
const char *DisSpecRegMemFpu0(struct XedDecodedInst *x, int group,
const char *b) {
return DisSpecRegMem(x, DisSpecFpu0(x, group), b);
}
const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
switch (x->op.opcode & 0xff) {
RCASE(0x00, "add Eb %Gb");
RCASE(0x01, "add Evqp %Gvqp");
RCASE(0x02, "add %Gb Eb");
RCASE(0x03, "add %Gvqp Evqp");
RCASE(0x04, "add %al Ib");
RCASE(0x05, "add %rAX Ivds");
RCASE(0x00, "ALU Eb %Gb");
RCASE(0x01, "ALU Evqp %Gvqp");
RCASE(0x02, "ALU %Gb Eb");
RCASE(0x03, "ALU %Gvqp Evqp");
RCASE(0x04, "ALU %al Ib");
RCASE(0x05, "ALU %rAX Ivds");
RCASE(0x06, "push %es");
RCASE(0x07, "pop %es");
RCASE(0x08, "or Eb %Gb");
RCASE(0x09, "or Evqp %Gvqp");
RCASE(0x0a, "or %Gb Eb");
RCASE(0x0b, "or %Gvqp Evqp");
RCASE(0x0c, "or %al Ib");
RCASE(0x0d, "or %rAX Ivds");
RCASE(0x08, "ALU Eb %Gb");
RCASE(0x09, "ALU Evqp %Gvqp");
RCASE(0x0a, "ALU %Gb Eb");
RCASE(0x0b, "ALU %Gvqp Evqp");
RCASE(0x0c, "ALU %al Ib");
RCASE(0x0d, "ALU %rAX Ivds");
RCASE(0x0e, "push %cs");
RCASE(0x0f, "pop %cs");
RCASE(0x10, "adc Eb %Gb");
RCASE(0x11, "adc Evqp %Gvqp");
RCASE(0x12, "adc %Gb Eb");
RCASE(0x13, "adc %Gvqp Evqp");
RCASE(0x14, "adc %al Ib");
RCASE(0x15, "adc %rAX Ivds");
RCASE(0x10, "ALU Eb %Gb");
RCASE(0x11, "ALU Evqp %Gvqp");
RCASE(0x12, "ALU %Gb Eb");
RCASE(0x13, "ALU %Gvqp Evqp");
RCASE(0x14, "ALU %al Ib");
RCASE(0x15, "ALU %rAX Ivds");
RCASE(0x16, "push %ss");
RCASE(0x17, "pop %ss");
RCASE(0x18, "sbb Eb %Gb");
RCASE(0x19, "sbb Evqp %Gvqp");
RCASE(0x1a, "sbb %Gb Eb");
RCASE(0x1b, "sbb %Gvqp Evqp");
RCASE(0x1c, "sbb %al Ib");
RCASE(0x1d, "sbb %rAX Ivds");
RCASE(0x18, "ALU Eb %Gb");
RCASE(0x19, "ALU Evqp %Gvqp");
RCASE(0x1a, "ALU %Gb Eb");
RCASE(0x1b, "ALU %Gvqp Evqp");
RCASE(0x1c, "ALU %al Ib");
RCASE(0x1d, "ALU %rAX Ivds");
RCASE(0x1e, "push %ds");
RCASE(0x1f, "pop %ds");
RCASE(0x20, "and Eb %Gb");
RCASE(0x21, "and Evqp %Gvqp");
RCASE(0x22, "and %Gb Eb");
RCASE(0x23, "and %Gvqp Evqp");
RCASE(0x24, "and %al Ib");
RCASE(0x25, "and %rAX Ivds");
RCASE(0x20, "ALU Eb %Gb");
RCASE(0x21, "ALU Evqp %Gvqp");
RCASE(0x22, "ALU %Gb Eb");
RCASE(0x23, "ALU %Gvqp Evqp");
RCASE(0x24, "ALU %al Ib");
RCASE(0x25, "ALU %rAX Ivds");
RCASE(0x26, "push %es");
RCASE(0x27, "pop %es");
RCASE(0x28, "sub Eb %Gb");
RCASE(0x29, "sub Evqp %Gvqp");
RCASE(0x28, "ALU Eb %Gb");
RCASE(0x29, "ALU Evqp %Gvqp");
RCASE(0x2a, "ALU %Gb Eb");
RCASE(0x2b, "ALU %Gvqp Evqp");
RCASE(0x2c, "ALU %al Ib");
RCASE(0x2d, "ALU %rAX Ivds");
RCASE(0x2F, "das");
RCASE(0x2a, "sub %Gb Eb");
RCASE(0x2b, "sub %Gvqp Evqp");
RCASE(0x2c, "sub %al Ib");
RCASE(0x2d, "sub %rAX Ivds");
RCASE(0x30, "xor Eb %Gb");
RCASE(0x31, "xor Evqp %Gvqp");
RCASE(0x32, "xor %Gb Eb");
RCASE(0x33, "xor %Gvqp Evqp");
RCASE(0x34, "xor %al Ib");
RCASE(0x35, "xor %rAX Ivds");
RCASE(0x30, "ALU Eb %Gb");
RCASE(0x31, "ALU Evqp %Gvqp");
RCASE(0x32, "ALU %Gb Eb");
RCASE(0x33, "ALU %Gvqp Evqp");
RCASE(0x34, "ALU %al Ib");
RCASE(0x35, "ALU %rAX Ivds");
RCASE(0x37, "aaa");
RCASE(0x38, "cmp Eb %Gb");
RCASE(0x39, "cmp Evqp %Gvqp");
RCASE(0x3A, "cmp %Gb Eb");
RCASE(0x3B, "cmp %Gvqp Evqp");
RCASE(0x3C, "cmp %al Ib");
RCASE(0x3D, "cmp %rAX Ivds");
RCASE(0x38, "ALU Eb %Gb");
RCASE(0x39, "ALU Evqp %Gvqp");
RCASE(0x3A, "ALU %Gb Eb");
RCASE(0x3B, "ALU %Gvqp Evqp");
RCASE(0x3C, "ALU %al Ib");
RCASE(0x3D, "ALU %rAX Ivds");
RCASE(0x3F, "aas");
RCASE(0x40 ... 0x47, "inc %Zv");
RCASE(0x48 ... 0x4f, "dec %Zv");
@ -167,26 +181,11 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
RCASE(0x6D, "insWL Yv %dx");
RCASE(0x6E, "outsb %dx Xb");
RCASE(0x6F, "outsWL %dx Xv");
RCASE(0x70, "joBT Jbs");
RCASE(0x71, "jnoBT Jbs");
RCASE(0x72, "jbBT Jbs");
RCASE(0x73, "jaeBT Jbs");
RCASE(0x74, "jeBT Jbs");
RCASE(0x75, "jneBT Jbs");
RCASE(0x76, "jbeBT Jbs");
RCASE(0x77, "jaBT Jbs");
RCASE(0x78, "jsBT Jbs");
RCASE(0x79, "jnsBT Jbs");
RCASE(0x7a, "jpBT Jbs");
RCASE(0x7b, "jnpBT Jbs");
RCASE(0x7c, "jlBT Jbs");
RCASE(0x7d, "jgeBT Jbs");
RCASE(0x7e, "jleBT Jbs");
RCASE(0x7f, "jgBT Jbs");
RCASE(0x80, "ALU Eb Ib");
RCASE(0x81, "ALU Evqp Ivds");
RCASE(0x82, "ALU Eb Ib");
RCASE(0x83, "ALU Evqp Ibs");
RCASE(0x70 ... 0x7f, "jCC Jbs");
RCASE(0x80, "ALU2 Eb Ib");
RCASE(0x81, "ALU2 Evqp Ivds");
RCASE(0x82, "ALU2 Eb Ib");
RCASE(0x83, "ALU2 Evqp Ibs");
RCASE(0x84, "test Eb %Gb");
RCASE(0x85, "test %Gvqp Evqp");
RCASE(0x86, "xchg %Gb Eb");
@ -202,6 +201,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
RCASE(0x91 ... 0x97, "xchg %Zvqp %rAX");
RCASE(0x98, "cwtl");
RCASE(0x99, "cltd");
RCASE(0x9A, "lcall Pvds Kvds");
RCASE(0x9B, "fwait");
RCASE(0x9C, "pushfWQ");
RCASE(0x9D, "popfWQ");
@ -234,6 +234,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
RCASE(0xC6, "mov Eb Ib");
RCASE(0xC7, "mov Evqp Ivds");
RCASE(0xC9, "leave");
RCASE(0xCA, "lret Iw");
RCASE(0xCB, "lret");
RCASE(0xCC, "int3");
RCASE(0xCD, "int Ib");
RCASE(0xD0, "BIT Eb $1");
@ -280,163 +282,36 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
switch (ModrmReg(x->op.rde)) {
RCASE(1, "fxch EST1");
RCASE(3, "fstps Msr %st");
case 0:
if (IsModrmRegister(x->op.rde)) {
return "fld EST";
} else {
return "flds Msr";
}
break;
case 2:
if (IsModrmRegister(x->op.rde)) {
return "fnop";
} else {
return "fsts Msr %st";
}
break;
case 4:
if (IsModrmRegister(x->op.rde)) {
return DisOpFpu0(x, 1);
} else {
return "fldenv Me";
}
break;
case 5:
if (IsModrmRegister(x->op.rde)) {
return DisOpFpu0(x, 2);
} else {
return "fldcw Mw";
}
break;
case 6:
if (IsModrmRegister(x->op.rde)) {
return DisOpFpu0(x, 3);
} else {
return "fnstenv M";
}
break;
case 7:
if (IsModrmRegister(x->op.rde)) {
return DisOpFpu0(x, 4);
} else {
return "fnstcw Mw";
}
break;
RCASE(0, DisSpecRegMem(x, "fld EST", "flds Msr"));
RCASE(2, DisSpecRegMem(x, "fnop", "fsts Msr %st"));
RCASE(4, DisSpecRegMemFpu0(x, 1, "fldenv Me"));
RCASE(5, DisSpecRegMemFpu0(x, 2, "fldcw Mw"));
RCASE(6, DisSpecRegMemFpu0(x, 3, "fnstenv M"));
RCASE(7, DisSpecRegMemFpu0(x, 4, "fnstcw Mw"));
}
break;
case 0xDA:
switch (ModrmReg(x->op.rde)) {
case 0:
if (!IsModrmRegister(x->op.rde)) {
return "fiaddl Mdi";
} else {
return "fcmovb %st EST";
}
break;
case 1:
if (!IsModrmRegister(x->op.rde)) {
return "fimull Mdi";
} else {
return "fcmove %st EST";
}
break;
case 2:
if (!IsModrmRegister(x->op.rde)) {
return "ficoml Mdi";
} else {
return "fcmovbe %st EST";
}
break;
case 3:
if (!IsModrmRegister(x->op.rde)) {
return "ficompl Mdi";
} else {
return "fcmovu %st EST";
}
break;
case 4:
if (!IsModrmRegister(x->op.rde)) {
return "fisubl Mdi";
} else {
return "fisubr Mdi";
}
break;
case 5:
if (!IsModrmRegister(x->op.rde)) {
return "fisubrl Mdi";
} else {
return "fucompp";
}
break;
case 6:
if (!IsModrmRegister(x->op.rde)) {
return "fidivl Mdi";
} else {
return UNKNOWN;
}
break;
case 7:
if (!IsModrmRegister(x->op.rde)) {
return "fidivrl Mdi";
} else {
return UNKNOWN;
}
break;
RCASE(0, DisSpecRegMem(x, "fcmovb %st EST", "fiaddl Mdi"));
RCASE(1, DisSpecRegMem(x, "fcmove %st EST", "fimull Mdi"));
RCASE(2, DisSpecRegMem(x, "fcmovbe %st EST", "ficoml Mdi"));
RCASE(3, DisSpecRegMem(x, "fcmovu %st EST", "ficompl Mdi"));
RCASE(4, DisSpecRegMem(x, "fisubr Mdi", "fisubl Mdi"));
RCASE(5, DisSpecRegMem(x, "fucompp", "fisubrl Mdi"));
RCASE(6, DisSpecRegMem(x, "fidivl Mdi", "UNKNOWN"));
RCASE(7, DisSpecRegMem(x, "fidivrl Mdi", "UNKNOWN"));
}
break;
case 0xDB:
switch (ModrmReg(x->op.rde)) {
case 0:
if (!IsModrmRegister(x->op.rde)) {
return "fildl Mdi";
} else {
return "fcmovnb %st EST";
}
break;
case 1:
if (!IsModrmRegister(x->op.rde)) {
return "fisttpl Mdi";
} else {
return "fcmovne %st EST";
}
break;
case 2:
if (!IsModrmRegister(x->op.rde)) {
return "fistl Mdi";
} else {
return "fcmovnbe %st EST";
}
break;
case 3:
if (!IsModrmRegister(x->op.rde)) {
return "fistpl Mdi";
} else {
return "fcmovnu %st EST";
}
break;
case 4:
return DisOpFpu0(x, 5);
case 5:
if (!IsModrmRegister(x->op.rde)) {
return "fldt Mer";
} else {
return "fucomi %st EST";
}
break;
case 6:
if (IsModrmRegister(x->op.rde)) {
return "fcomi %st EST";
} else {
return UNKNOWN;
}
break;
case 7:
if (!IsModrmRegister(x->op.rde)) {
return "fstpt Mer";
} else {
return UNKNOWN;
}
break;
RCASE(0, DisSpecRegMem(x, "fcmovnb %st EST", "fildl Mdi"));
RCASE(1, DisSpecRegMem(x, "fcmovne %st EST", "fisttpl Mdi"));
RCASE(2, DisSpecRegMem(x, "fcmovnbe %st EST", "fistl Mdi"));
RCASE(3, DisSpecRegMem(x, "fcmovnu %st EST", "fistpl Mdi"));
RCASE(4, DisSpecFpu0(x, 5));
RCASE(5, DisSpecRegMem(x, "fucomi %st EST", "fldt Mer"));
RCASE(6, DisSpecRegMem(x, "fcomi %st EST", UNKNOWN));
RCASE(7, DisSpecRegMem(x, UNKNOWN, "fstpt Mer"));
}
break;
case 0xD8:
@ -590,22 +465,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
RCASE(0x2E, Osz(x->op.rde) ? "ucomisd %Vsd Wsd" : "ucomiss %Vss Wss");
RCASE(0x2F, Osz(x->op.rde) ? "comisd %Vsd Wsd" : "comiss %Vss Wss");
RCASE(0x31, "rdtsc");
RCASE(0x40, "cmovo %Gvqp Evqp");
RCASE(0x41, "cmovno %Gvqp Evqp");
RCASE(0x42, "cmovb %Gvqp Evqp");
RCASE(0x43, "cmovae %Gvqp Evqp");
RCASE(0x44, "cmove %Gvqp Evqp");
RCASE(0x45, "cmovne %Gvqp Evqp");
RCASE(0x46, "cmovbe %Gvqp Evqp");
RCASE(0x47, "cmova %Gvqp Evqp");
RCASE(0x48, "cmovs %Gvqp Evqp");
RCASE(0x49, "cmovns %Gvqp Evqp");
RCASE(0x4a, "cmovp %Gvqp Evqp");
RCASE(0x4b, "cmovnp %Gvqp Evqp");
RCASE(0x4c, "cmovl %Gvqp Evqp");
RCASE(0x4d, "cmovge %Gvqp Evqp");
RCASE(0x4e, "cmovle %Gvqp Evqp");
RCASE(0x4f, "cmovg %Gvqp Evqp");
RCASE(0x40 ... 0x4f, "cmovCC %Gvqp Evqp");
RCASE(0x52, DisOpVpsWpsVssWss(x, p, "rsqrt"));
RCASE(0x53, DisOpVpsWpsVssWss(x, p, "rcp"));
RCASE(0x54, DisOpVpdWpdVpsWps(x, p, "and"));
@ -635,38 +495,8 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
RCASE(0x74, DisOpPqQqVdqWdq(x, p, "pcmpeqb"));
RCASE(0x75, DisOpPqQqVdqWdq(x, p, "pcmpeqw"));
RCASE(0x76, DisOpPqQqVdqWdq(x, p, "pcmpeqd"));
RCASE(0x80, "jo Jvds");
RCASE(0x81, "jno Jvds");
RCASE(0x82, "jb Jvds");
RCASE(0x83, "jae Jvds");
RCASE(0x84, "je Jvds");
RCASE(0x85, "jne Jvds");
RCASE(0x86, "jbe Jvds");
RCASE(0x87, "ja Jvds");
RCASE(0x88, "js Jvds");
RCASE(0x89, "jns Jvds");
RCASE(0x8a, "jp Jvds");
RCASE(0x8b, "jnp Jvds");
RCASE(0x8c, "jl Jvds");
RCASE(0x8d, "jge Jvds");
RCASE(0x8e, "jle Jvds");
RCASE(0x8f, "jg Jvds");
RCASE(0x90, "seto Eb");
RCASE(0x91, "setno Eb");
RCASE(0x92, "setb Eb");
RCASE(0x93, "setnb Eb");
RCASE(0x94, "sete Eb");
RCASE(0x95, "setne Eb");
RCASE(0x96, "setbe Eb");
RCASE(0x97, "seta Eb");
RCASE(0x98, "sets Eb");
RCASE(0x99, "setns Eb");
RCASE(0x9A, "setp Eb");
RCASE(0x9B, "setnp Eb");
RCASE(0x9C, "setl Eb");
RCASE(0x9D, "setge Eb");
RCASE(0x9E, "setle Eb");
RCASE(0x9F, "setg Eb");
RCASE(0x80 ... 0x8f, "jCC Jvds");
RCASE(0x90 ... 0x9f, "setCC Jvds");
RCASE(0xA0, "push %fs");
RCASE(0xA1, "pop %fs");
RCASE(0xA2, "cpuid");

55
tool/build/lib/flags.c Normal file
View 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 "tool/build/lib/flags.h"
bool GetParity(uint8_t b) {
b ^= b >> 4;
b ^= b >> 2;
b ^= b >> 1;
return ~b & 1;
}
void ImportFlags(struct Machine *m, uint64_t flags) {
uint64_t old, mask = 0;
mask |= 1u << FLAGS_CF;
mask |= 1u << FLAGS_PF;
mask |= 1u << FLAGS_AF;
mask |= 1u << FLAGS_ZF;
mask |= 1u << FLAGS_SF;
mask |= 1u << FLAGS_TF;
mask |= 1u << FLAGS_IF;
mask |= 1u << FLAGS_DF;
mask |= 1u << FLAGS_OF;
mask |= 1u << FLAGS_NT;
mask |= 1u << FLAGS_AC;
mask |= 1u << FLAGS_ID;
m->flags = (flags & mask) | (m->flags & ~mask);
m->flags = SetFlag(m->flags, FLAGS_RF, false);
m->flags = SetLazyParityByte(m->flags, !((m->flags >> FLAGS_PF) & 1));
}
uint64_t ExportFlags(uint64_t flags) {
flags = SetFlag(flags, FLAGS_IOPL, 3);
flags = SetFlag(flags, FLAGS_F1, true);
flags = SetFlag(flags, FLAGS_F0, false);
flags = flags & ~(1ull << FLAGS_PF);
flags |= GetLazyParityBool(flags) << FLAGS_PF;
return flags;
}

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_
#include "tool/build/lib/machine.h"
#define FLAGS_CF 0
#define FLAGS_VF 1
@ -23,18 +24,12 @@
#define FLAGS_VIP 20
#define FLAGS_ID 21
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define GetLazyParityBool(f) GetParity((f) >> 24)
#define SetLazyParityByte(f, x) (((f) & ~0xFF000000u) | ((x)&0xFFu) << 24)
#define GetParity(WORD) \
({ \
unsigned Byte = (WORD); \
Byte ^= Byte >> 4; \
Byte ^= Byte >> 2; \
Byte ^= Byte >> 1; \
~Byte & 1; \
})
#define GetFlag(FLAGS, BIT) \
({ \
autotype(FLAGS) Flags = (FLAGS); \
@ -66,13 +61,10 @@
Flags; \
})
forceinline uint64_t ExportFlags(uint64_t flags) {
flags = SetFlag(flags, FLAGS_IOPL, 3);
flags = SetFlag(flags, FLAGS_F1, true);
flags = SetFlag(flags, FLAGS_F0, false);
flags = flags & ~(1ull << FLAGS_PF);
flags |= GetLazyParityBool(flags) << FLAGS_PF;
return flags;
}
bool GetParity(uint8_t);
uint64_t ExportFlags(uint64_t);
void ImportFlags(struct Machine *, uint64_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_ */

View file

@ -298,8 +298,7 @@ static long double FpuRound(struct Machine *m, long double x) {
}
static void FpuCompare(struct Machine *m, long double y) {
long double x;
x = St0(m);
long double x = St0(m);
m->fpu.c1 = false;
if (!isunordered(x, y)) {
m->fpu.c0 = x < y;
@ -452,7 +451,7 @@ static void OpFsincos(struct Machine *m) {
static void OpFpatan(struct Machine *m) {
FpuClearRoundup(m);
FpuSetStPop(m, 1, atan2l(St0(m), St1(m)));
FpuSetStPop(m, 1, atan2l(St1(m), St0(m)));
}
static void OpFcom(struct Machine *m) {
@ -704,8 +703,7 @@ static void OpFincstp(struct Machine *m) {
}
static void OpFxtract(struct Machine *m) {
long double x;
x = St0(m);
long double x = St0(m);
FpuSetSt0(m, logbl(x));
FpuPush(m, significandl(x));
}
@ -766,30 +764,44 @@ static void OpFldl(struct Machine *m) {
FpuPush(m, FpuGetMemoryDouble(m));
}
static long double Fld1(void) {
return 1;
}
static long double Fldl2t(void) {
return 0xd.49a784bcd1b8afep-2L; /* log₂10 */
}
static long double Fldl2e(void) {
return 0xb.8aa3b295c17f0bcp-3L; /* log₂𝑒 */
}
static long double Fldpi(void) {
return 0x1.921fb54442d1846ap+1L; /* π */
}
static long double Fldlg2(void) {
return 0x9.a209a84fbcff799p-5L; /* log₁₀2 */
}
static long double Fldln2(void) {
return 0xb.17217f7d1cf79acp-4L; /* logₑ2 */
}
static long double Fldz(void) {
return 0;
}
static void OpFldConstant(struct Machine *m) {
long double x;
switch (ModrmRm(m->xedd->op.rde)) {
case 0:
x = fld1();
break;
case 1:
x = fldl2t();
break;
case 2:
x = fldl2e();
break;
case 3:
x = fldpi();
break;
case 4:
x = fldlg2();
break;
case 5:
x = fldln2();
break;
case 6:
x = fldz();
break;
CASE(0, x = Fld1());
CASE(1, x = Fldl2t());
CASE(2, x = Fldl2e());
CASE(3, x = Fldpi());
CASE(4, x = Fldlg2());
CASE(5, x = Fldln2());
CASE(6, x = Fldz());
default:
OpUd(m, m->xedd->op.rde);
}

View file

@ -19,16 +19,24 @@
*/
#include "libc/conv/itoa.h"
#include "libc/str/str.h"
#include "tool/build/lib/dis.h"
#include "tool/build/lib/high.h"
struct DisHigh *g_dis_high;
struct High g_high;
char *DisHigh(char *p, int h) {
if (h != -1) {
char *HighStart(char *p, int h) {
if (h) {
p = stpcpy(p, "\e[38;5;");
p += uint64toarray_radix10(h, p);
} else {
p = stpcpy(p, "\e[39");
p = stpcpy(p, "m");
g_high.active = true;
}
return stpcpy(p, "m");
return p;
}
char *HighEnd(char *p) {
if (g_high.active) {
p = stpcpy(p, "\e[39m");
g_high.active = false;
}
return p;
}

23
tool/build/lib/high.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct High {
bool active;
uint8_t keyword;
uint8_t reg;
uint8_t literal;
uint8_t label;
uint8_t comment;
uint8_t quote;
};
extern struct High g_high;
char *HighStart(char *, int);
char *HighEnd(char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_ */

View file

@ -52,18 +52,33 @@ static void DecodeInstruction(struct Machine *m, uint8_t *p, unsigned n) {
}
}
static noinline void LoadInstructionSlow(struct Machine *m, uint64_t ip) {
unsigned i;
uint8_t *addr;
uint8_t copy[15], *toil;
i = 0x1000 - (ip & 0xfff);
addr = ResolveAddress(m, ip);
if ((toil = FindReal(m, ip + i))) {
memcpy(copy, addr, i);
memcpy(copy + i, toil, 15 - i);
DecodeInstruction(m, copy, 15);
} else {
DecodeInstruction(m, addr, i);
}
}
void LoadInstruction(struct Machine *m) {
uint64_t ip;
unsigned i, key;
uint8_t *addr, *toil, copy[15];
unsigned key;
uint8_t *addr;
ip = Read64(m->cs) + MaskAddress(m->mode & 3, m->ip);
key = ip & (ARRAYLEN(m->icache) - 1);
m->xedd = (struct XedDecodedInst *)m->icache[key];
if ((i = 0x1000 - (ip & 0xfff)) >= 15) {
if (ROUNDDOWN(ip, 0x1000) == m->codevirt && ip) {
if ((ip & 0xfff) < 0x1000 - 15) {
if (ip - (ip & 0xfff) == m->codevirt && ip) {
addr = m->codereal + (ip & 0xfff);
} else {
m->codevirt = ROUNDDOWN(ip, 0x1000);
m->codevirt = ip - (ip & 0xfff);
m->codereal = ResolveAddress(m, m->codevirt);
addr = m->codereal + (ip & 0xfff);
}
@ -71,13 +86,6 @@ void LoadInstruction(struct Machine *m) {
DecodeInstruction(m, addr, 15);
}
} else {
addr = ResolveAddress(m, ip);
if ((toil = FindReal(m, ip + i))) {
memcpy(copy, addr, i);
memcpy(copy + i, toil, 15 - i);
DecodeInstruction(m, copy, 15);
} else {
DecodeInstruction(m, addr, i);
}
LoadInstructionSlow(m, ip);
}
}

View file

@ -52,6 +52,7 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
fstart = felf + ROUNDDOWN(phdr->p_offset, align);
fend = felf + ROUNDUP(phdr->p_offset + phdr->p_filesz, align);
bsssize = vend - vbss;
m->brk = MAX(m->brk, vend);
CHECK_GE(vend, vstart);
CHECK_GE(fend, fstart);
CHECK_LE(felf, fstart);
@ -120,7 +121,7 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
DCHECK_NOTNULL(prog);
elf->prog = prog;
if ((fd = open(prog, O_RDONLY)) == -1 ||
(fstat(fd, &st) == -1 || !st.st_size) || !S_ISREG(st.st_mode)) {
(fstat(fd, &st) == -1 || !st.st_size) /* || !S_ISREG(st.st_mode) */) {
fputs(prog, stderr);
fputs(": not found\n", stderr);
exit(1);

View file

@ -50,6 +50,12 @@
#include "tool/build/lib/throw.h"
#include "tool/build/lib/time.h"
#define OpLfence OpNoop
#define OpMfence OpNoop
#define OpSfence OpNoop
#define OpClflush OpNoop
#define OpHintNopEv OpNoop
typedef void (*nexgen32e_f)(struct Machine *, uint32_t);
static uint64_t ReadMemory(uint32_t rde, uint8_t p[8]) {
@ -130,38 +136,7 @@ static bool IsGreater(struct Machine *m) {
(GetFlag(m->flags, FLAGS_SF) == GetFlag(m->flags, FLAGS_OF));
}
static void ImportFlags(struct Machine *m, uint64_t flags) {
uint64_t old, mask = 0;
mask |= 1u << FLAGS_CF;
mask |= 1u << FLAGS_PF;
mask |= 1u << FLAGS_AF;
mask |= 1u << FLAGS_ZF;
mask |= 1u << FLAGS_SF;
mask |= 1u << FLAGS_TF;
mask |= 1u << FLAGS_IF;
mask |= 1u << FLAGS_DF;
mask |= 1u << FLAGS_OF;
mask |= 1u << FLAGS_NT;
mask |= 1u << FLAGS_AC;
mask |= 1u << FLAGS_ID;
m->flags = (flags & mask) | (m->flags & ~mask);
m->flags = SetFlag(m->flags, FLAGS_RF, false);
m->flags = SetLazyParityByte(m->flags, !((m->flags >> FLAGS_PF) & 1));
}
static void OpLfence(struct Machine *m, uint32_t rde) {
}
static void OpMfence(struct Machine *m, uint32_t rde) {
}
static void OpSfence(struct Machine *m, uint32_t rde) {
}
static void OpClflush(struct Machine *m, uint32_t rde) {
}
static void OpWutNopEv(struct Machine *m, uint32_t rde) {
static void OpNoop(struct Machine *m, uint32_t rde) {
}
static void OpCmc(struct Machine *m, uint32_t rde) {
@ -216,27 +191,27 @@ static void OpLeaGvqpM(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde), ComputeAddress(m, rde));
}
static void OpPushSeg(struct Machine *m, uint32_t rde) {
static relegated void OpPushSeg(struct Machine *m, uint32_t rde) {
uint8_t seg = (m->xedd->op.opcode & 070) >> 3;
Push(m, rde, Read64(GetSegment(m, rde, seg)) >> 4);
}
static void OpPopSeg(struct Machine *m, uint32_t rde) {
static relegated void OpPopSeg(struct Machine *m, uint32_t rde) {
uint8_t seg = (m->xedd->op.opcode & 070) >> 3;
Write64(GetSegment(m, rde, seg), Pop(m, rde, 0) << 4);
}
static void OpMovEvqpSw(struct Machine *m, uint32_t rde) {
static relegated void OpMovEvqpSw(struct Machine *m, uint32_t rde) {
WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde),
Read64(GetSegment(m, rde, ModrmReg(rde))) >> 4);
}
static void OpMovSwEvqp(struct Machine *m, uint32_t rde) {
static relegated void OpMovSwEvqp(struct Machine *m, uint32_t rde) {
Write64(GetSegment(m, rde, ModrmReg(rde)),
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)) << 4);
}
static void OpJmpf(struct Machine *m, uint32_t rde) {
static relegated void OpJmpf(struct Machine *m, uint32_t rde) {
Write64(m->cs, m->xedd->op.uimm0 << 4);
m->ip = m->xedd->op.disp;
}
@ -474,7 +449,8 @@ static void OpBit(struct Machine *m, uint32_t rde) {
SetWriteAddr(m, v, 1 << w);
}
}
y = 1ull << bit;
y = 1;
y <<= bit;
x = ReadMemory(rde, p);
m->flags = SetFlag(m->flags, FLAGS_CF, !!(y & x));
switch (op) {
@ -495,7 +471,7 @@ static void OpBit(struct Machine *m, uint32_t rde) {
WriteRegisterOrMemory(rde, p, z);
}
static void OpConvert1(struct Machine *m, uint32_t rde) {
static void OpSax(struct Machine *m, uint32_t rde) {
if (Rexw(rde)) {
Write64(m->ax, (int32_t)Read32(m->ax));
} else if (!Osz(rde)) {
@ -505,7 +481,7 @@ static void OpConvert1(struct Machine *m, uint32_t rde) {
}
}
static void OpConvert2(struct Machine *m, uint32_t rde) {
static void OpConvert(struct Machine *m, uint32_t rde) {
if (Rexw(rde)) {
Write64(m->dx, Read64(m->ax) & 0x8000000000000000 ? 0xffffffffffffffff : 0);
} else if (!Osz(rde)) {
@ -530,7 +506,7 @@ static void OpBswapZvqp(struct Machine *m, uint32_t rde) {
((x & 0xff000000) >> 030 | (x & 0x000000ff) << 030 |
(x & 0x00ff0000) >> 010 | (x & 0x0000ff00) << 010));
} else {
Write16(RegRexbSrm(m, rde), ((x & 0x00ff) << 010 | (x & 0xff00) << 010));
Write16(RegRexbSrm(m, rde), (x & 0x00ff) << 010 | (x & 0xff00) << 010);
}
}
@ -625,18 +601,41 @@ static void OpMovswGvqpEw(struct Machine *m, uint32_t rde) {
}
static void OpMovsxdGdqpEd(struct Machine *m, uint32_t rde) {
uint64_t x;
uint8_t *p;
x = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde));
if (!Rexw(rde)) x &= 0xffffffff; /* wut */
Write64(RegRexrReg(m, rde), x);
Write64(RegRexrReg(m, rde),
(int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde)));
}
static void OpAlub(struct Machine *m, uint32_t rde) {
uint8_t *a;
a = GetModrmRegisterBytePointerWrite(m, rde);
Write8(a, kAlu[(m->xedd->op.opcode & 070) >> 3][0](
Read8(a), Read8(ByteRexrReg(m, rde)), &m->flags));
static void Alub(struct Machine *m, uint32_t rde, aluop_f op) {
uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde);
Write8(a, op(Read8(a), Read8(ByteRexrReg(m, rde)), &m->flags));
}
static void OpAlubAdd(struct Machine *m, uint32_t rde) {
Alub(m, rde, Add8);
}
static void OpAlubOr(struct Machine *m, uint32_t rde) {
Alub(m, rde, Or8);
}
static void OpAlubAdc(struct Machine *m, uint32_t rde) {
Alub(m, rde, Adc8);
}
static void OpAlubSbb(struct Machine *m, uint32_t rde) {
Alub(m, rde, Sbb8);
}
static void OpAlubAnd(struct Machine *m, uint32_t rde) {
Alub(m, rde, And8);
}
static void OpAlubSub(struct Machine *m, uint32_t rde) {
Alub(m, rde, Sub8);
}
static void OpAlubXor(struct Machine *m, uint32_t rde) {
Alub(m, rde, Xor8);
}
static void AlubRo(struct Machine *m, uint32_t rde, aluop_f op) {
@ -652,11 +651,38 @@ static void OpAlubTest(struct Machine *m, uint32_t rde) {
AlubRo(m, rde, And8);
}
static void OpAlubFlip(struct Machine *m, uint32_t rde) {
static void AlubFlip(struct Machine *m, uint32_t rde, aluop_f op) {
Write8(ByteRexrReg(m, rde),
kAlu[(m->xedd->op.opcode & 070) >> 3][0](
Read8(ByteRexrReg(m, rde)),
Read8(GetModrmRegisterBytePointerRead(m, rde)), &m->flags));
op(Read8(ByteRexrReg(m, rde)),
Read8(GetModrmRegisterBytePointerRead(m, rde)), &m->flags));
}
static void OpAlubFlipAdd(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Add8);
}
static void OpAlubFlipOr(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Or8);
}
static void OpAlubFlipAdc(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Adc8);
}
static void OpAlubFlipSbb(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Sbb8);
}
static void OpAlubFlipAnd(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, And8);
}
static void OpAlubFlipSub(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Sub8);
}
static void OpAlubFlipXor(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Xor8);
}
static void AlubFlipRo(struct Machine *m, uint32_t rde, aluop_f op) {
@ -765,9 +791,36 @@ static void OpAluwiReg(struct Machine *m, uint32_t rde) {
}
}
static void OpAluAlIb(struct Machine *m, uint32_t rde) {
Write8(m->ax, kAlu[(m->xedd->op.opcode & 070) >> 3][0](
Read8(m->ax), m->xedd->op.uimm0, &m->flags));
static void AluAlIb(struct Machine *m, aluop_f op) {
Write8(m->ax, op(Read8(m->ax), m->xedd->op.uimm0, &m->flags));
}
static void OpAluAlIbAdd(struct Machine *m, uint32_t rde) {
AluAlIb(m, Add8);
}
static void OpAluAlIbOr(struct Machine *m, uint32_t rde) {
AluAlIb(m, Or8);
}
static void OpAluAlIbAdc(struct Machine *m, uint32_t rde) {
AluAlIb(m, Adc8);
}
static void OpAluAlIbSbb(struct Machine *m, uint32_t rde) {
AluAlIb(m, Sbb8);
}
static void OpAluAlIbAnd(struct Machine *m, uint32_t rde) {
AluAlIb(m, And8);
}
static void OpAluAlIbSub(struct Machine *m, uint32_t rde) {
AluAlIb(m, Sub8);
}
static void OpAluAlIbXor(struct Machine *m, uint32_t rde) {
AluAlIb(m, Xor8);
}
static void OpAluRaxIvds(struct Machine *m, uint32_t rde) {
@ -831,18 +884,19 @@ static void OpBsubiImm(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, m->xedd->op.uimm0);
}
static void LoadFarPointer(struct Machine *m, uint32_t rde, uint8_t seg[8]) {
static relegated void LoadFarPointer(struct Machine *m, uint32_t rde,
uint8_t seg[8]) {
uint32_t fp;
fp = Read32(ComputeReserveAddressRead4(m, rde));
Write64(seg, (fp & 0x0000ffff) << 4);
Write16(RegRexrReg(m, rde), fp >> 16);
}
static void OpLes(struct Machine *m, uint32_t rde) {
static relegated void OpLes(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->es);
}
static void OpLds(struct Machine *m, uint32_t rde) {
static relegated void OpLds(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->ds);
}
@ -853,14 +907,6 @@ static void OpPushImm(struct Machine *m, uint32_t rde) {
Push(m, rde, m->xedd->op.uimm0);
}
static void OpRet0(struct Machine *m, uint32_t rde) {
OpRet(m, rde, 0);
}
static void OpRetImm(struct Machine *m, uint32_t rde) {
OpRet(m, rde, m->xedd->op.uimm0);
}
static void Interrupt(struct Machine *m, uint32_t rde, int i) {
HaltMachine(m, i);
}
@ -1213,17 +1259,18 @@ static void OpNegEb(struct Machine *m, uint32_t rde) {
AluEb(m, rde, Neg8);
}
static const nexgen32e_f kOp0f6[] = {
OpAlubiTest,
OpAlubiTest,
OpNotEb,
OpNegEb,
OpMulAxAlEbUnsigned,
OpMulAxAlEbSigned,
OpDivAlAhAxEbUnsigned,
OpDivAlAhAxEbSigned,
};
static void Op0f6(struct Machine *m, uint32_t rde) {
static const nexgen32e_f kOp0f6[] = {
OpAlubiTest,
OpAlubiTest,
OpNotEb,
OpNegEb,
OpMulAxAlEbUnsigned,
OpMulAxAlEbSigned,
OpDivAlAhAxEbUnsigned,
OpDivAlAhAxEbSigned,
};
kOp0f6[ModrmReg(rde)](m, rde);
}
@ -1239,17 +1286,18 @@ static void OpNegEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_NEG]);
}
static const nexgen32e_f kOp0f7[] = {
OpTestEvqpIvds,
OpTestEvqpIvds,
OpNotEvqp,
OpNegEvqp,
OpMulRdxRaxEvqpUnsigned,
OpMulRdxRaxEvqpSigned,
OpDivRdxRaxEvqpUnsigned,
OpDivRdxRaxEvqpSigned,
};
static void Op0f7(struct Machine *m, uint32_t rde) {
static const nexgen32e_f kOp0f7[] = {
OpTestEvqpIvds,
OpTestEvqpIvds,
OpNotEvqp,
OpNegEvqp,
OpMulRdxRaxEvqpUnsigned,
OpMulRdxRaxEvqpSigned,
OpDivRdxRaxEvqpUnsigned,
OpDivRdxRaxEvqpSigned,
};
kOp0f7[ModrmReg(rde)](m, rde);
}
@ -1274,9 +1322,10 @@ static void OpDecEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_DEC]);
}
static const nexgen32e_f kOp0ff[] = {OpIncEvqp, OpDecEvqp, OpCallEq, OpUd,
OpJmpEq, OpUd, OpPushEvq, OpUd};
static void Op0ff(struct Machine *m, uint32_t rde) {
static const nexgen32e_f kOp0ff[] = {OpIncEvqp, OpDecEvqp, OpCallEq, OpUd,
OpJmpEq, OpUd, OpPushEvq, OpUd};
kOp0ff[ModrmReg(rde)](m, rde);
}
@ -1295,57 +1344,6 @@ static void Op101(struct Machine *m, uint32_t rde) {
OpUd(m, rde);
}
static void Op171(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 2:
OpSseUdqIb(m, rde, kOpSseUdqIbPsrlw);
break;
case 4:
OpSseUdqIb(m, rde, kOpSseUdqIbPsraw);
break;
case 6:
OpSseUdqIb(m, rde, kOpSseUdqIbPsllw);
break;
default:
OpUd(m, rde);
}
}
static void Op172(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 2:
OpSseUdqIb(m, rde, kOpSseUdqIbPsrld);
break;
case 4:
OpSseUdqIb(m, rde, kOpSseUdqIbPsrad);
break;
case 6:
OpSseUdqIb(m, rde, kOpSseUdqIbPslld);
break;
default:
OpUd(m, rde);
}
}
static void Op173(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 2:
OpSseUdqIb(m, rde, kOpSseUdqIbPsrlq);
break;
case 3:
OpSseUdqIb(m, rde, kOpSseUdqIbPsrldq);
break;
case 6:
OpSseUdqIb(m, rde, kOpSseUdqIbPsllq);
break;
case 7:
OpSseUdqIb(m, rde, kOpSseUdqIbPslldq);
break;
default:
OpUd(m, rde);
}
}
static void OpDoubleShift(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x;
@ -1386,6 +1384,8 @@ static void OpSalc(struct Machine *m, uint32_t rde) {
static void OpNopEv(struct Machine *m, uint32_t rde) {
if (ModrmMod(rde) == 0b01 && ModrmReg(rde) == 0 && ModrmRm(rde) == 0b101) {
OpBofram(m, rde);
} else {
OpNoop(m, rde);
}
}
@ -1394,63 +1394,65 @@ static void OpNop(struct Machine *m, uint32_t rde) {
OpXchgZvqp(m, rde);
} else if (Rep(rde) == 3) {
OpPause(m, rde);
} else {
OpNoop(m, rde);
}
}
static const nexgen32e_f kNexgen32e[] = {
[0x000] = OpAlub,
[0x000] = OpAlubAdd,
[0x001] = OpAluw,
[0x002] = OpAlubFlip,
[0x002] = OpAlubFlipAdd,
[0x003] = OpAluwFlip,
[0x004] = OpAluAlIb,
[0x004] = OpAluAlIbAdd,
[0x005] = OpAluRaxIvds,
[0x006] = OpPushSeg,
[0x007] = OpPopSeg,
[0x008] = OpAlub,
[0x008] = OpAlubOr,
[0x009] = OpAluw,
[0x00A] = OpAlubFlip,
[0x00A] = OpAlubFlipOr,
[0x00B] = OpAluwFlip,
[0x00C] = OpAluAlIb,
[0x00C] = OpAluAlIbOr,
[0x00D] = OpAluRaxIvds,
[0x00E] = OpPushSeg,
[0x00F] = OpPopSeg,
[0x010] = OpAlub,
[0x010] = OpAlubAdc,
[0x011] = OpAluw,
[0x012] = OpAlubFlip,
[0x012] = OpAlubFlipAdc,
[0x013] = OpAluwFlip,
[0x014] = OpAluAlIb,
[0x014] = OpAluAlIbAdc,
[0x015] = OpAluRaxIvds,
[0x016] = OpPushSeg,
[0x017] = OpPopSeg,
[0x018] = OpAlub,
[0x018] = OpAlubSbb,
[0x019] = OpAluw,
[0x01A] = OpAlubFlip,
[0x01A] = OpAlubFlipSbb,
[0x01B] = OpAluwFlip,
[0x01C] = OpAluAlIb,
[0x01C] = OpAluAlIbSbb,
[0x01D] = OpAluRaxIvds,
[0x01E] = OpPushSeg,
[0x01F] = OpPopSeg,
[0x020] = OpAlub,
[0x020] = OpAlubAnd,
[0x021] = OpAluw,
[0x022] = OpAlubFlip,
[0x022] = OpAlubFlipAnd,
[0x023] = OpAluwFlip,
[0x024] = OpAluAlIb,
[0x024] = OpAluAlIbAnd,
[0x025] = OpAluRaxIvds,
[0x026] = OpPushSeg,
[0x027] = OpPopSeg,
[0x028] = OpAlub,
[0x028] = OpAlubSub,
[0x029] = OpAluw,
[0x02A] = OpAlubFlip,
[0x02A] = OpAlubFlipSub,
[0x02B] = OpAluwFlip,
[0x02C] = OpAluAlIb,
[0x02C] = OpAluAlIbSub,
[0x02D] = OpAluRaxIvds,
[0x02E] = OpUd,
[0x02F] = OpDas,
[0x030] = OpAlub,
[0x030] = OpAlubXor,
[0x031] = OpAluw,
[0x032] = OpAlubFlip,
[0x032] = OpAlubFlipXor,
[0x033] = OpAluwFlip,
[0x034] = OpAluAlIb,
[0x034] = OpAluAlIbXor,
[0x035] = OpAluRaxIvds,
[0x036] = OpUd,
[0x037] = OpAaa,
@ -1550,9 +1552,9 @@ static const nexgen32e_f kNexgen32e[] = {
[0x095] = OpXchgZvqp,
[0x096] = OpXchgZvqp,
[0x097] = OpXchgZvqp,
[0x098] = OpConvert1,
[0x099] = OpConvert2,
[0x09A] = OpUd,
[0x098] = OpSax,
[0x099] = OpConvert,
[0x09A] = OpCallf,
[0x09B] = OpFwait,
[0x09C] = OpPushf,
[0x09D] = OpPopf,
@ -1592,16 +1594,16 @@ static const nexgen32e_f kNexgen32e[] = {
[0x0BF] = OpMovZvqpIvqp,
[0x0C0] = OpBsubiImm,
[0x0C1] = OpBsuwiImm,
[0x0C2] = OpRetImm,
[0x0C3] = OpRet0,
[0x0C2] = OpRet,
[0x0C3] = OpRet,
[0x0C4] = OpLes,
[0x0C5] = OpLds,
[0x0C6] = OpMovEbIb,
[0x0C7] = OpMovEvqpIvds,
[0x0C8] = OpUd,
[0x0C9] = OpLeave,
[0x0CA] = OpUd,
[0x0CB] = OpUd,
[0x0CA] = OpRetf,
[0x0CB] = OpRetf,
[0x0CC] = OpInterrupt3,
[0x0CD] = OpInterruptImm,
[0x0CE] = OpUd,
@ -1667,7 +1669,7 @@ static const nexgen32e_f kNexgen32e[] = {
[0x10A] = OpUd,
[0x10B] = OpUd,
[0x10C] = OpUd,
[0x10D] = OpWutNopEv,
[0x10D] = OpHintNopEv,
[0x10E] = OpUd,
[0x10F] = OpUd,
[0x110] = OpMov0f10,
@ -1678,12 +1680,12 @@ static const nexgen32e_f kNexgen32e[] = {
[0x115] = OpUnpckhpsd,
[0x116] = OpMov0f16,
[0x117] = OpMov0f17,
[0x118] = OpWutNopEv,
[0x119] = OpWutNopEv,
[0x11A] = OpWutNopEv,
[0x11B] = OpWutNopEv,
[0x11C] = OpWutNopEv,
[0x11D] = OpWutNopEv,
[0x118] = OpHintNopEv,
[0x119] = OpHintNopEv,
[0x11A] = OpHintNopEv,
[0x11B] = OpHintNopEv,
[0x11C] = OpHintNopEv,
[0x11D] = OpHintNopEv,
[0x11E] = OpUd,
[0x11F] = OpNopEv,
[0x120] = OpUd,

View file

@ -137,12 +137,13 @@ struct Machine {
uint32_t i;
void *p[6];
} freelist;
int64_t brk;
int64_t bofram[2];
jmp_buf onhalt;
int64_t faultaddr;
uint8_t stash[4096];
uint8_t xmmtype[2][8];
uint8_t icache[2048][40] aligned(8);
uint8_t icache[4096 / 4][40] aligned(16);
struct MachineFds fds;
} aligned(64);

View file

@ -22,12 +22,45 @@
#include "tool/build/lib/buffer.h"
#include "tool/build/lib/mda.h"
#define kBlink 1
#define kVisible 2
#define kUnderline 4
#define kBold 8
#define kReverse 16
/**
* Decodes Monochrome Display Adapter attributes.
* @see https://www.seasip.info/VintagePC/mda.html
*/
static uint8_t DecodeMdaAttributes(int8_t a) {
uint8_t r = 0;
if (a & 0x77) {
if ((a & 0x77) == 0x70) r |= kReverse;
if ((a & 0x07) == 0x01) r |= kUnderline;
if (a & 0x08) r |= kBold;
if (a < 0) r |= kBlink;
r |= kVisible;
}
return r;
}
void DrawMda(struct Panel *p, uint8_t v[25][80][2]) {
unsigned y, x, n;
unsigned y, x, n, a, b;
n = MIN(25, p->bottom - p->top);
for (y = 0; y < n; ++y) {
a = -1;
for (x = 0; x < 80; ++x) {
if (v[y][x][1]) {
b = DecodeMdaAttributes(v[y][x][1]);
if (a != b) {
a = b;
AppendStr(&p->lines[y], "\e[0");
if (a & kBold) AppendStr(&p->lines[y], ";1");
if (a & kUnderline) AppendStr(&p->lines[y], ";4");
if (a & kBlink) AppendStr(&p->lines[y], ";5");
if (a & kReverse) AppendStr(&p->lines[y], ";7");
AppendChar(&p->lines[y], 'm');
}
if (a) {
AppendWide(&p->lines[y], kCp437[v[y][x][0]]);
} else {
AppendChar(&p->lines[y], ' ');

View file

@ -26,29 +26,54 @@
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/throw.h"
/**
* Byte register offsets.
*
* for (i = 0; i < 2; ++i) { // rex
* for (j = 0; j < 2; ++j) { // rexb, or rexr
* for (k = 0; k < 8; ++k) { // reg, rm, or srm
* kByteReg[i << 4 | j << 3 | k] =
* i ? (j << 3 | k) * 8 : (k & 0b11) * 8 + ((k & 0b100) >> 2);
* }
* }
* }
*/
const uint8_t kByteReg[32] = {0x00, 0x08, 0x10, 0x18, 0x01, 0x09, 0x11, 0x19,
0x00, 0x08, 0x10, 0x18, 0x01, 0x09, 0x11, 0x19,
0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38,
0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78};
static relegated noinline int64_t ComputeAddressReal(const struct Machine *m,
uint32_t rde, uint8_t *s,
uint64_t i) {
switch (ModrmRm(rde)) {
case 0:
i += Read16(m->bx);
i += Read16(m->si);
break;
case 1:
i += Read16(m->bx);
i += Read16(m->di);
break;
case 2:
s = m->ss;
i += Read16(m->bp);
i += Read16(m->si);
break;
case 3:
s = m->ss;
i += Read16(m->bp);
i += Read16(m->di);
break;
case 4:
i += Read16(m->si);
break;
case 5:
i += Read16(m->di);
break;
case 6:
if (ModrmMod(rde)) {
s = m->ss;
i += Read16(m->bp);
}
break;
case 7:
i += Read16(m->bx);
break;
default:
unreachable;
}
i &= 0xffff;
return AddSegment(m, rde, i, s);
}
int64_t ComputeAddress(const struct Machine *m, uint32_t rde) {
uint64_t i;
uint8_t *s;
uint8_t *s = m->ds;
uint64_t i = m->xedd->op.disp;
DCHECK(!IsModrmRegister(rde));
s = m->ds;
i = m->xedd->op.disp;
if (Eamode(rde) != XED_MODE_REAL) {
if (!SibExists(rde)) {
if (IsRipRelative(rde)) {
@ -75,47 +100,10 @@ int64_t ComputeAddress(const struct Machine *m, uint32_t rde) {
if (Eamode(rde) == XED_MODE_LEGACY) {
i &= 0xffffffff;
}
return AddSegment(m, rde, i, s);
} else {
switch (ModrmRm(rde)) {
case 0:
i += Read16(m->bx);
i += Read16(m->si);
break;
case 1:
i += Read16(m->bx);
i += Read16(m->di);
break;
case 2:
s = m->ss;
i += Read16(m->bp);
i += Read16(m->si);
break;
case 3:
s = m->ss;
i += Read16(m->bp);
i += Read16(m->di);
break;
case 4:
i += Read16(m->si);
break;
case 5:
i += Read16(m->di);
break;
case 6:
if (ModrmMod(rde)) {
s = m->ss;
i += Read16(m->bp);
}
break;
case 7:
i += Read16(m->bx);
break;
default:
unreachable;
}
i &= 0xffff;
return ComputeAddressReal(m, rde, s, i);
}
return AddSegment(m, rde, i, s);
}
void *ComputeReserveAddressRead(struct Machine *m, uint32_t rde, size_t n) {

View file

@ -2,8 +2,6 @@
#define COSMOPOLITAN_TOOL_BUILD_LIB_MODRM_H_
#include "tool/build/lib/abp.h"
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define Rex(x) ((x & 000000000020) >> 004)
#define Osz(x) ((x & 000000000040) >> 005)
@ -21,12 +19,16 @@ COSMOPOLITAN_C_START_
#define ModrmReg(x) ((x & 000000000007) >> 000)
#define ModrmSrm(x) ((x & 000000070000) >> 014)
#define ModrmMod(x) ((x & 000060000000) >> 026)
#define Modrm(x) (ModrmMod(x) << 6 | ModrmReg(x) << 3 | ModrmRm(x))
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define RexbBase(m, x) (Rexb(x) << 3 | m->xedd->op.base)
#define AddrByteReg(m, k) ((uint8_t *)m->reg + kByteReg[k])
#define ByteRexrReg(m, x) AddrByteReg(m, (x & 00000000037) >> 0)
#define ByteRexbRm(m, x) AddrByteReg(m, (x & 00000007600) >> 7)
#define ByteRexbSrm(m, x) AddrByteReg(m, (x & 00000370000) >> 12)
#define RexbBase(m, x) (Rexb(x) << 3 | m->xedd->op.base)
#define RegSrm(m, x) Abp8(m->reg[(x & 00000070000) >> 12])
#define RegRexbRm(m, x) Abp8(m->reg[RexbRm(x)])
#define RegRexbSrm(m, x) Abp8(m->reg[(x & 00000170000) >> 12])

View file

@ -36,12 +36,13 @@
* @param p is panel list in logically sorted order
* @param tyn is terminal height in cells
* @param txn is terminal width in cells
* @return bytes emitted, or -1 w/ errno
* @return -1 w/ errno if an error happened
* @see nblack's notcurses project too!
*/
ssize_t PrintPanels(int fd, long pn, struct Panel p[pn], long tyn, long txn) {
wint_t wc;
ssize_t rc;
size_t wrote;
struct Buffer b, *l;
int x, y, i, j, width;
enum { kUtf8, kAnsi, kAnsiCsi } state;

View file

@ -53,10 +53,11 @@ static uint64_t *GetPageTable(pml4t_t p, long i, void *NewPhysicalPage(void)) {
}
static void PtFinder(uint64_t *a, uint64_t *b, uint64_t n, pml4t_t pd, int k) {
unsigned i;
uint64_t e, c;
unsigned start;
for (start = (*b >> k) & 511; *b - *a < n && ((*b >> k) & 511) >= start;) {
e = pd[(*b >> k) & 511];
while (*b - *a < n) {
i = (*b >> k) & 511;
e = pd[i];
c = ROUNDUP(*b + 1, 1 << k);
if (!IsValidPage(e)) {
*b = c;
@ -65,6 +66,9 @@ static void PtFinder(uint64_t *a, uint64_t *b, uint64_t n, pml4t_t pd, int k) {
} else {
*a = *b = c;
}
if (((*b >> k) & 511) < i) {
break;
}
}
}

View file

@ -17,9 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/arraylist2.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/conv/itoa.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
@ -32,13 +34,18 @@
#include "tool/build/lib/pty.h"
struct MachinePty *MachinePtyNew(void) {
return xcalloc(1, sizeof(struct MachinePty));
struct MachinePty *pty;
pty = xcalloc(1, sizeof(struct MachinePty));
MachinePtyResize(pty, 25, 80);
return pty;
}
void MachinePtyResize(struct MachinePty *pty, int yn, int xn) {
unsigned y, ym, xm, y0;
uint32_t *wcs, *fgs, *bgs, *prs;
if (yn <= 0 || xn <= 0) return;
if (xn < 80) xn = 80;
if (yn < 25) yn = 25;
if (xn == pty->xn && yn == pty->yn) return;
wcs = xcalloc(yn * xn, 4);
fgs = xcalloc(yn * xn, 4);
bgs = xcalloc(yn * xn, 4);
@ -92,7 +99,9 @@ static void MachinePtyNewline(struct MachinePty *pty) {
pty->x = 0;
if (++pty->y == pty->yn) {
--pty->y;
MachinePtyScroll(pty);
if (!(pty->conf & kMachinePtyNoopost)) {
MachinePtyScroll(pty);
}
}
}
@ -335,6 +344,38 @@ static void MachinePtyShowCursor(struct MachinePty *pty) {
pty->conf &= ~kMachinePtyNocursor;
}
static void MachinePtyReportCursorPosition(struct MachinePty *pty) {
char *p;
char buf[2 + 10 + 1 + 10 + 1];
p = buf;
*p++ = '\e';
*p++ = '[';
p += uint64toarray_radix10((pty->y + 1) & 0xffffffff, p);
*p++ = ';';
p += uint64toarray_radix10((pty->x + 1) & 0xffffffff, p);
*p++ = 'R';
CONCAT(&pty->input.p, &pty->input.i, &pty->input.n, buf, p - buf);
}
static void MachinePtyCsiN(struct MachinePty *pty) {
switch (atoi(pty->esc.s)) {
case 6:
MachinePtyReportCursorPosition(pty);
break;
default:
break;
}
}
static void MachinePtyCsiScrollUp(struct MachinePty *pty) {
int n;
n = atoi(pty->esc.s);
n = MAX(1, n);
while (n--) {
MachinePtyScroll(pty);
}
}
static void MachinePtyCsi(struct MachinePty *pty) {
switch (pty->esc.s[pty->esc.i - 1]) {
case 'A':
@ -362,6 +403,12 @@ static void MachinePtyCsi(struct MachinePty *pty) {
case 'm':
MachinePtySelectGraphicsRendition(pty);
break;
case 'n':
MachinePtyCsiN(pty);
break;
case 'S':
MachinePtyCsiScrollUp(pty);
break;
case 'l':
if (strcmp(pty->esc.s, "?25l") == 0) {
MachinePtyHideCursor(pty);
@ -389,7 +436,6 @@ static void MachinePtyEscAppend(struct MachinePty *pty, char c) {
ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
int i;
const uint8_t *p;
if (!pty->yn || !pty->xn) return 0;
for (p = data, i = 0; i < n; ++i) {
switch (pty->state) {
case kMachinePtyAscii:
@ -408,6 +454,14 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
case '\n':
MachinePtyNewline(pty);
break;
case 0177:
case '\b':
pty->x = MAX(0, pty->x - 1);
break;
case '\f':
break;
case '\a':
break;
default:
SetMachinePtyCell(pty, p[i]);
break;
@ -483,47 +537,87 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
return n;
}
ssize_t MachinePtyWriteInput(struct MachinePty *pty, const void *data,
size_t n) {
const char *p = data;
CONCAT(&pty->input.p, &pty->input.i, &pty->input.n, data, n);
if (!(pty->conf & kMachinePtyNoecho)) {
MachinePtyWrite(pty, data, n);
}
return n;
}
ssize_t MachinePtyRead(struct MachinePty *pty, void *buf, size_t size) {
char *p;
size_t n;
n = MIN(size, pty->input.i);
if (!(pty->conf & kMachinePtyNocanon)) {
if ((p = memchr(pty->input.p, '\n', n))) {
n = MIN(n, pty->input.p - p + 1);
} else {
n = 0;
}
}
memcpy(buf, pty->input.p, n);
memcpy(pty->input.p, pty->input.p + n, pty->input.i - n);
pty->input.i -= n;
return n;
}
void MachinePtyAppendLine(struct MachinePty *pty, struct Buffer *buf,
unsigned y) {
bool atcursor;
uint32_t x, i, fg, bg, pr, wc, w;
if (y >= pty->yn) return;
for (fg = bg = pr = x = 0; x < pty->xn; x += w) {
i = y * pty->xn + x;
wc = pty->wcs[i];
w = MAX(0, wcwidth(wc));
if (w) {
if (pty->prs[i] != pr || pty->fgs[i] != fg || pty->bgs[i] != bg) {
fg = pty->fgs[i];
bg = pty->bgs[i];
pr = pty->prs[i];
AppendStr(buf, "\e[0");
if (pr & kMachinePtyBold) AppendStr(buf, ";1");
if (pr & kMachinePtyFaint) AppendStr(buf, ";2");
if (pr & kMachinePtyFlip) AppendStr(buf, ";7");
if (pr & kMachinePtyFg) {
if (pr & kMachinePtyTrue) {
AppendFmt(buf, ";38;2;%d;%d;%d", (fg & 0x0000ff) >> 000,
(fg & 0x00ff00) >> 010, (fg & 0xff0000) >> 020);
} else {
AppendFmt(buf, ";38;5;%d", fg);
}
}
if (pr & kMachinePtyBg) {
if (pr & kMachinePtyTrue) {
AppendFmt(buf, ";48;2;%d;%d;%d", (bg & 0x0000ff) >> 000,
(bg & 0x00ff00) >> 010, (bg & 0xff0000) >> 020);
} else {
AppendFmt(buf, ";48;5;%d", bg);
}
}
AppendStr(buf, "m");
atcursor = y == pty->y && x == pty->x;
if ((w && atcursor) ||
(pty->prs[i] != pr || pty->fgs[i] != fg || pty->bgs[i] != bg)) {
fg = pty->fgs[i];
bg = pty->bgs[i];
pr = pty->prs[i];
AppendStr(buf, "\e[0");
if (w && atcursor) {
pr ^= kMachinePtyFlip;
}
if (pr & kMachinePtyBold) AppendStr(buf, ";1");
if (pr & kMachinePtyFaint) AppendStr(buf, ";2");
if (pr & kMachinePtyBlink) AppendStr(buf, ";5");
if (pr & kMachinePtyFlip) AppendStr(buf, ";7");
if (pr & kMachinePtyFg) {
if (pr & kMachinePtyTrue) {
AppendFmt(buf, ";38;2;%d;%d;%d", (fg & 0x0000ff) >> 000,
(fg & 0x00ff00) >> 010, (fg & 0xff0000) >> 020);
} else {
AppendFmt(buf, ";38;5;%d", fg);
}
}
if (pr & kMachinePtyBg) {
if (pr & kMachinePtyTrue) {
AppendFmt(buf, ";48;2;%d;%d;%d", (bg & 0x0000ff) >> 000,
(bg & 0x00ff00) >> 010, (bg & 0xff0000) >> 020);
} else {
AppendFmt(buf, ";48;5;%d", bg);
}
}
AppendStr(buf, "m");
}
if (w) {
AppendWide(buf, wc);
} else {
w = 1;
if (y == pty->y && x == pty->x) {
if (atcursor) {
if (!(pty->conf & kMachinePtyNocursor)) {
AppendStr(buf, "\e[5m▂\e[25m");
if (pty->conf & kMachinePtyBlinkcursor) {
AppendStr(buf, "\e[5m");
}
AppendWide(buf, u'');
if (pty->conf & kMachinePtyBlinkcursor) {
AppendStr(buf, "\e[25m");
}
}
} else {
AppendChar(buf, ' ');

View file

@ -8,17 +8,22 @@
#define kMachinePtyBold 0x08
#define kMachinePtyFaint 0x10
#define kMachinePtyFlip 0x20
#define kMachinePtyBlink 0x40
#define kMachinePtyNocursor 0x01
#define kMachinePtyNocursor 0x01
#define kMachinePtyBlinkcursor 0x02
#define kMachinePtyNocanon 0x04
#define kMachinePtyNoecho 0x08
#define kMachinePtyNoopost 0x10
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct MachinePty {
uint32_t yn;
uint32_t xn;
uint32_t y;
uint32_t x;
int y;
int x;
int yn;
int xn;
uint32_t pr;
uint32_t fg;
uint32_t bg;
@ -38,12 +43,18 @@ struct MachinePty {
unsigned i;
char s[64];
} esc;
struct MachinePtyInput {
size_t i, n;
char *p;
} input;
};
void MachinePtyFree(struct MachinePty *);
struct MachinePty *MachinePtyNew(void) nodiscard;
void MachinePtyResize(struct MachinePty *, int, int);
ssize_t MachinePtyRead(struct MachinePty *, void *, size_t);
ssize_t MachinePtyWrite(struct MachinePty *, const void *, size_t);
ssize_t MachinePtyWriteInput(struct MachinePty *, const void *, size_t);
void MachinePtyAppendLine(struct MachinePty *, struct Buffer *, unsigned);
COSMOPOLITAN_C_END_

View file

@ -100,19 +100,7 @@
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/sse.h"
union MachineVector {
float f32[4];
double f64[2];
int8_t i8[16];
int16_t i16[8];
int32_t i32[4];
int64_t i64[2];
uint8_t u8[16];
uint16_t u16[8];
uint32_t u32[4];
uint64_t u64[2];
};
#include "tool/build/lib/throw.h"
static void SsePsubb(void *b, const void *a) {
psubb(b, b, a);
@ -711,29 +699,81 @@ void OpSsePmulld(struct Machine *m, uint32_t rde) {
OpSse(m, rde, SsePmulld);
}
void OpSseUdqIb(struct Machine *m, uint32_t rde, enum OpSseUdqIbKernel kernel) {
static void SseUdqIb(struct Machine *m, uint32_t rde, int kernel) {
void *y;
uint8_t i;
union MachineVector x;
uint8_t x[16];
i = m->xedd->op.uimm0;
memcpy(&x, XmmRexbRm(m, rde), 16);
y = XmmRexbRm(m, rde);
switch (kernel) {
CASE(kOpSseUdqIbPsrlw, (psrlw)(x.u16, x.u16, i));
CASE(kOpSseUdqIbPsraw, (psraw)(x.i16, x.i16, i));
CASE(kOpSseUdqIbPsllw, (psllw)(x.u16, x.u16, i));
CASE(kOpSseUdqIbPsrld, (psrld)(x.u32, x.u32, i));
CASE(kOpSseUdqIbPsrad, (psrad)(x.i32, x.i32, i));
CASE(kOpSseUdqIbPslld, (pslld)(x.u32, x.u32, i));
CASE(kOpSseUdqIbPsrlq, (psrlq)(x.u64, x.u64, i));
CASE(kOpSseUdqIbPsrldq, (psrldq)(x.u8, x.u8, i));
CASE(kOpSseUdqIbPsllq, (psllq)(x.u64, x.u64, i));
CASE(kOpSseUdqIbPslldq, (pslldq)(x.u8, x.u8, i));
CASE(0, (psrlw)((void *)x, y, i));
CASE(1, (psraw)((void *)x, y, i));
CASE(2, (psllw)((void *)x, y, i));
CASE(3, (psrld)((void *)x, y, i));
CASE(4, (psrad)((void *)x, y, i));
CASE(5, (pslld)((void *)x, y, i));
CASE(6, (psrlq)((void *)x, y, i));
CASE(7, (psrldq)((void *)x, y, i));
CASE(8, (psllq)((void *)x, y, i));
CASE(9, (pslldq)((void *)x, y, i));
default:
unreachable;
}
if (Osz(rde)) {
memcpy(XmmRexbRm(m, rde), &x, 16);
memcpy(XmmRexbRm(m, rde), x, 16);
} else {
memcpy(XmmRexbRm(m, rde), &x, 8);
memcpy(XmmRexbRm(m, rde), x, 8);
}
}
void Op171(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 2:
SseUdqIb(m, rde, 0);
break;
case 4:
SseUdqIb(m, rde, 1);
break;
case 6:
SseUdqIb(m, rde, 2);
break;
default:
OpUd(m, rde);
}
}
void Op172(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 2:
SseUdqIb(m, rde, 3);
break;
case 4:
SseUdqIb(m, rde, 4);
break;
case 6:
SseUdqIb(m, rde, 5);
break;
default:
OpUd(m, rde);
}
}
void Op173(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 2:
SseUdqIb(m, rde, 6);
break;
case 3:
SseUdqIb(m, rde, 7);
break;
case 6:
SseUdqIb(m, rde, 8);
break;
case 7:
SseUdqIb(m, rde, 9);
break;
default:
OpUd(m, rde);
}
}

View file

@ -4,96 +4,83 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef void (*sse_f)(void *, void *, void *);
enum OpSseUdqIbKernel {
kOpSseUdqIbPsrlw,
kOpSseUdqIbPsraw,
kOpSseUdqIbPsllw,
kOpSseUdqIbPsrld,
kOpSseUdqIbPsrad,
kOpSseUdqIbPslld,
kOpSseUdqIbPsrlq,
kOpSseUdqIbPsrldq,
kOpSseUdqIbPsllq,
kOpSseUdqIbPslldq,
};
void OpSseUdqIb(struct Machine *, uint32_t, enum OpSseUdqIbKernel);
void OpSsePalignr(struct Machine *, uint32_t);
void OpSsePunpcklbw(struct Machine *, uint32_t);
void OpSsePunpcklwd(struct Machine *, uint32_t);
void OpSsePunpckldq(struct Machine *, uint32_t);
void OpSsePacksswb(struct Machine *, uint32_t);
void OpSsePcmpgtb(struct Machine *, uint32_t);
void OpSsePcmpgtw(struct Machine *, uint32_t);
void OpSsePcmpgtd(struct Machine *, uint32_t);
void OpSsePackuswb(struct Machine *, uint32_t);
void OpSsePunpckhbw(struct Machine *, uint32_t);
void OpSsePunpckhwd(struct Machine *, uint32_t);
void OpSsePunpckhdq(struct Machine *, uint32_t);
void Op171(struct Machine *, uint32_t);
void Op172(struct Machine *, uint32_t);
void Op173(struct Machine *, uint32_t);
void OpSsePabsb(struct Machine *, uint32_t);
void OpSsePabsd(struct Machine *, uint32_t);
void OpSsePabsw(struct Machine *, uint32_t);
void OpSsePackssdw(struct Machine *, uint32_t);
void OpSsePunpcklqdq(struct Machine *, uint32_t);
void OpSsePunpckhqdq(struct Machine *, uint32_t);
void OpSsePcmpeqb(struct Machine *, uint32_t);
void OpSsePcmpeqw(struct Machine *, uint32_t);
void OpSsePcmpeqd(struct Machine *, uint32_t);
void OpSsePsrlwv(struct Machine *, uint32_t);
void OpSsePsrldv(struct Machine *, uint32_t);
void OpSsePsrlqv(struct Machine *, uint32_t);
void OpSsePacksswb(struct Machine *, uint32_t);
void OpSsePackuswb(struct Machine *, uint32_t);
void OpSsePaddb(struct Machine *, uint32_t);
void OpSsePaddd(struct Machine *, uint32_t);
void OpSsePaddq(struct Machine *, uint32_t);
void OpSsePmullw(struct Machine *, uint32_t);
void OpSsePsubusb(struct Machine *, uint32_t);
void OpSsePsubusw(struct Machine *, uint32_t);
void OpSsePminub(struct Machine *, uint32_t);
void OpSsePand(struct Machine *, uint32_t);
void OpSsePaddusb(struct Machine *, uint32_t);
void OpSsePaddusw(struct Machine *, uint32_t);
void OpSsePmaxub(struct Machine *, uint32_t);
void OpSsePandn(struct Machine *, uint32_t);
void OpSsePavgb(struct Machine *, uint32_t);
void OpSsePsrawv(struct Machine *, uint32_t);
void OpSsePsradv(struct Machine *, uint32_t);
void OpSsePavgw(struct Machine *, uint32_t);
void OpSsePmulhuw(struct Machine *, uint32_t);
void OpSsePmulhw(struct Machine *, uint32_t);
void OpSsePsubsb(struct Machine *, uint32_t);
void OpSsePsubsw(struct Machine *, uint32_t);
void OpSsePminsw(struct Machine *, uint32_t);
void OpSsePor(struct Machine *, uint32_t);
void OpSsePaddsb(struct Machine *, uint32_t);
void OpSsePaddsw(struct Machine *, uint32_t);
void OpSsePmaxsw(struct Machine *, uint32_t);
void OpSsePxor(struct Machine *, uint32_t);
void OpSsePsllwv(struct Machine *, uint32_t);
void OpSsePslldv(struct Machine *, uint32_t);
void OpSsePsllqv(struct Machine *, uint32_t);
void OpSsePmuludq(struct Machine *, uint32_t);
void OpSsePmaddwd(struct Machine *, uint32_t);
void OpSsePsadbw(struct Machine *, uint32_t);
void OpSsePsubb(struct Machine *, uint32_t);
void OpSsePsubw(struct Machine *, uint32_t);
void OpSsePsubd(struct Machine *, uint32_t);
void OpSsePsubq(struct Machine *, uint32_t);
void OpSsePaddb(struct Machine *, uint32_t);
void OpSsePaddusb(struct Machine *, uint32_t);
void OpSsePaddusw(struct Machine *, uint32_t);
void OpSsePaddw(struct Machine *, uint32_t);
void OpSsePaddd(struct Machine *, uint32_t);
void OpSsePshufb(struct Machine *, uint32_t);
void OpSsePhaddw(struct Machine *, uint32_t);
void OpSsePalignr(struct Machine *, uint32_t);
void OpSsePand(struct Machine *, uint32_t);
void OpSsePandn(struct Machine *, uint32_t);
void OpSsePavgb(struct Machine *, uint32_t);
void OpSsePavgw(struct Machine *, uint32_t);
void OpSsePcmpeqb(struct Machine *, uint32_t);
void OpSsePcmpeqd(struct Machine *, uint32_t);
void OpSsePcmpeqw(struct Machine *, uint32_t);
void OpSsePcmpgtb(struct Machine *, uint32_t);
void OpSsePcmpgtd(struct Machine *, uint32_t);
void OpSsePcmpgtw(struct Machine *, uint32_t);
void OpSsePhaddd(struct Machine *, uint32_t);
void OpSsePhaddsw(struct Machine *, uint32_t);
void OpSsePmaddubsw(struct Machine *, uint32_t);
void OpSsePhsubw(struct Machine *, uint32_t);
void OpSsePhaddw(struct Machine *, uint32_t);
void OpSsePhsubd(struct Machine *, uint32_t);
void OpSsePhsubsw(struct Machine *, uint32_t);
void OpSsePsignb(struct Machine *, uint32_t);
void OpSsePsignw(struct Machine *, uint32_t);
void OpSsePsignd(struct Machine *, uint32_t);
void OpSsePhsubw(struct Machine *, uint32_t);
void OpSsePmaddubsw(struct Machine *, uint32_t);
void OpSsePmaddwd(struct Machine *, uint32_t);
void OpSsePmaxsw(struct Machine *, uint32_t);
void OpSsePmaxub(struct Machine *, uint32_t);
void OpSsePminsw(struct Machine *, uint32_t);
void OpSsePminub(struct Machine *, uint32_t);
void OpSsePmulhrsw(struct Machine *, uint32_t);
void OpSsePabsb(struct Machine *, uint32_t);
void OpSsePabsw(struct Machine *, uint32_t);
void OpSsePabsd(struct Machine *, uint32_t);
void OpSsePmulhuw(struct Machine *, uint32_t);
void OpSsePmulhw(struct Machine *, uint32_t);
void OpSsePmulld(struct Machine *, uint32_t);
void OpSsePmullw(struct Machine *, uint32_t);
void OpSsePmuludq(struct Machine *, uint32_t);
void OpSsePor(struct Machine *, uint32_t);
void OpSsePsadbw(struct Machine *, uint32_t);
void OpSsePshufb(struct Machine *, uint32_t);
void OpSsePsignb(struct Machine *, uint32_t);
void OpSsePsignd(struct Machine *, uint32_t);
void OpSsePsignw(struct Machine *, uint32_t);
void OpSsePslldv(struct Machine *, uint32_t);
void OpSsePsllqv(struct Machine *, uint32_t);
void OpSsePsllwv(struct Machine *, uint32_t);
void OpSsePsradv(struct Machine *, uint32_t);
void OpSsePsrawv(struct Machine *, uint32_t);
void OpSsePsrldv(struct Machine *, uint32_t);
void OpSsePsrlqv(struct Machine *, uint32_t);
void OpSsePsrlwv(struct Machine *, uint32_t);
void OpSsePsubb(struct Machine *, uint32_t);
void OpSsePsubd(struct Machine *, uint32_t);
void OpSsePsubq(struct Machine *, uint32_t);
void OpSsePsubsb(struct Machine *, uint32_t);
void OpSsePsubsw(struct Machine *, uint32_t);
void OpSsePsubusb(struct Machine *, uint32_t);
void OpSsePsubusw(struct Machine *, uint32_t);
void OpSsePsubw(struct Machine *, uint32_t);
void OpSsePunpckhbw(struct Machine *, uint32_t);
void OpSsePunpckhdq(struct Machine *, uint32_t);
void OpSsePunpckhqdq(struct Machine *, uint32_t);
void OpSsePunpckhwd(struct Machine *, uint32_t);
void OpSsePunpcklbw(struct Machine *, uint32_t);
void OpSsePunpckldq(struct Machine *, uint32_t);
void OpSsePunpcklqdq(struct Machine *, uint32_t);
void OpSsePunpcklwd(struct Machine *, uint32_t);
void OpSsePxor(struct Machine *, uint32_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -56,12 +56,10 @@ static uint64_t ReadStackWord(uint8_t *p, uint32_t osz) {
}
}
void Push(struct Machine *m, uint32_t rde, uint64_t x) {
static void PushN(struct Machine *m, uint32_t rde, uint64_t x, unsigned osz) {
uint64_t v;
void *p[2];
uint8_t b[8];
unsigned osz;
osz = kStackOsz[m->xedd->op.osz][Mode(rde)];
switch (Eamode(rde)) {
case XED_MODE_REAL:
v = (Read32(m->sp) - osz) & 0xffff;
@ -84,18 +82,21 @@ void Push(struct Machine *m, uint32_t rde, uint64_t x) {
EndStore(m, v, osz, p, b);
}
void Push(struct Machine *m, uint32_t rde, uint64_t x) {
PushN(m, rde, x, kStackOsz[m->xedd->op.osz][Mode(rde)]);
}
void OpPushZvq(struct Machine *m, uint32_t rde) {
unsigned osz;
osz = kStackOsz[m->xedd->op.osz][Mode(rde)];
Push(m, rde, ReadStackWord(RegRexbSrm(m, rde), osz));
PushN(m, rde, ReadStackWord(RegRexbSrm(m, rde), osz), osz);
}
uint64_t Pop(struct Machine *m, uint32_t rde, uint16_t extra) {
static uint64_t PopN(struct Machine *m, uint32_t rde, uint16_t extra,
unsigned osz) {
uint64_t v;
void *p[2];
uint8_t b[8];
unsigned osz;
osz = kStackOsz[m->xedd->op.osz][Mode(rde)];
switch (Eamode(rde)) {
case XED_MODE_LONG:
v = Read64(m->sp);
@ -117,10 +118,16 @@ uint64_t Pop(struct Machine *m, uint32_t rde, uint16_t extra) {
return ReadStackWord(AccessRam(m, v, osz, p, b, true), osz);
}
uint64_t Pop(struct Machine *m, uint32_t rde, uint16_t extra) {
return PopN(m, rde, extra, kStackOsz[m->xedd->op.osz][Mode(rde)]);
}
void OpPopZvq(struct Machine *m, uint32_t rde) {
uint64_t x;
x = Pop(m, rde, 0);
switch (kStackOsz[m->xedd->op.osz][Mode(rde)]) {
unsigned osz;
osz = kStackOsz[m->xedd->op.osz][Mode(rde)];
x = PopN(m, rde, 0, osz);
switch (osz) {
case 8:
case 4:
Write64(RegRexbSrm(m, rde), x);
@ -175,8 +182,8 @@ void OpLeave(struct Machine *m, uint32_t rde) {
}
}
void OpRet(struct Machine *m, uint32_t rde, uint16_t n) {
m->ip = Pop(m, rde, n);
void OpRet(struct Machine *m, uint32_t rde) {
m->ip = Pop(m, rde, m->xedd->op.uimm0);
}
void OpBofram(struct Machine *m, uint32_t rde) {
@ -203,7 +210,7 @@ void OpPopEvq(struct Machine *m, uint32_t rde) {
Pop(m, rde, 0));
}
static void Pushaw(struct Machine *m, uint32_t rde) {
static relegated void Pushaw(struct Machine *m, uint32_t rde) {
uint16_t v;
uint8_t b[8][2];
memcpy(b[0], m->di, 2);
@ -218,7 +225,7 @@ static void Pushaw(struct Machine *m, uint32_t rde) {
VirtualRecv(m, Read64(m->ss) + v, b, sizeof(b));
}
static void Pushad(struct Machine *m, uint32_t rde) {
static relegated void Pushad(struct Machine *m, uint32_t rde) {
uint32_t v;
uint8_t b[8][4];
memcpy(b[0], m->di, 4);
@ -233,7 +240,35 @@ static void Pushad(struct Machine *m, uint32_t rde) {
VirtualRecv(m, Read64(m->ss) + v, b, sizeof(b));
}
void OpPusha(struct Machine *m, uint32_t rde) {
static relegated void Popaw(struct Machine *m, uint32_t rde) {
uint8_t b[8][2];
VirtualSend(m, b, Read64(m->ss) + Read16(m->sp), sizeof(b));
Write16(m->sp, (Read32(m->sp) + sizeof(b)) & 0xffff);
memcpy(m->di, b[0], 2);
memcpy(m->si, b[1], 2);
memcpy(m->bp, b[2], 2);
memcpy(m->sp, b[3], 2);
memcpy(m->bx, b[4], 2);
memcpy(m->dx, b[5], 2);
memcpy(m->cx, b[6], 2);
memcpy(m->ax, b[7], 2);
}
static relegated void Popad(struct Machine *m, uint32_t rde) {
uint8_t b[8][4];
VirtualSend(m, b, Read64(m->ss) + Read32(m->sp), sizeof(b));
Write64(m->sp, (Read32(m->sp) + sizeof(b)) & 0xffffffff);
memcpy(m->di, b[0], 4);
memcpy(m->si, b[1], 4);
memcpy(m->bp, b[2], 4);
memcpy(m->sp, b[3], 4);
memcpy(m->bx, b[4], 4);
memcpy(m->dx, b[5], 4);
memcpy(m->cx, b[6], 4);
memcpy(m->ax, b[7], 4);
}
relegated void OpPusha(struct Machine *m, uint32_t rde) {
switch (Eamode(rde)) {
case XED_MODE_REAL:
Pushaw(m, rde);
@ -248,35 +283,7 @@ void OpPusha(struct Machine *m, uint32_t rde) {
}
}
static void Popaw(struct Machine *m, uint32_t rde) {
uint8_t b[8][2];
VirtualSend(m, b, Read64(m->ss) + Read16(m->sp), sizeof(b));
Write16(m->sp, (Read32(m->sp) + sizeof(b)) & 0xffff);
memcpy(m->di, b[0], 2);
memcpy(m->si, b[1], 2);
memcpy(m->bp, b[2], 2);
memcpy(m->sp, b[3], 2);
memcpy(m->bx, b[4], 2);
memcpy(m->dx, b[5], 2);
memcpy(m->cx, b[6], 2);
memcpy(m->ax, b[7], 2);
}
static void Popad(struct Machine *m, uint32_t rde) {
uint8_t b[8][4];
VirtualSend(m, b, Read64(m->ss) + Read32(m->sp), sizeof(b));
Write64(m->sp, (Read32(m->sp) + sizeof(b)) & 0xffffffff);
memcpy(m->di, b[0], 4);
memcpy(m->si, b[1], 4);
memcpy(m->bp, b[2], 4);
memcpy(m->sp, b[3], 4);
memcpy(m->bx, b[4], 4);
memcpy(m->dx, b[5], 4);
memcpy(m->cx, b[6], 4);
memcpy(m->ax, b[7], 4);
}
void OpPopa(struct Machine *m, uint32_t rde) {
relegated void OpPopa(struct Machine *m, uint32_t rde) {
switch (Eamode(rde)) {
case XED_MODE_REAL:
Popaw(m, rde);
@ -290,3 +297,15 @@ void OpPopa(struct Machine *m, uint32_t rde) {
unreachable;
}
}
relegated void OpCallf(struct Machine *m, uint32_t rde) {
Push(m, rde, Read64(m->cs) >> 4);
Push(m, rde, m->ip);
Write64(m->cs, m->xedd->op.uimm0 << 4);
m->ip = m->xedd->op.disp & (Osz(rde) ? 0xffff : 0xffffffff);
}
relegated void OpRetf(struct Machine *m, uint32_t rde) {
m->ip = Pop(m, rde, 0);
Write64(m->cs, Pop(m, rde, m->xedd->op.uimm0) << 4);
}

View file

@ -7,7 +7,8 @@ COSMOPOLITAN_C_START_
void Push(struct Machine *, uint32_t, uint64_t);
uint64_t Pop(struct Machine *, uint32_t, uint16_t);
void OpCallJvds(struct Machine *, uint32_t);
void OpRet(struct Machine *, uint32_t, uint16_t);
void OpRet(struct Machine *, uint32_t);
void OpRetf(struct Machine *, uint32_t);
void OpLeave(struct Machine *, uint32_t);
void OpCallEq(struct Machine *, uint32_t);
void OpBofram(struct Machine *, uint32_t);
@ -20,6 +21,7 @@ void PushVq(struct Machine *, uint32_t);
void OpJmpEq(struct Machine *, uint32_t);
void OpPusha(struct Machine *, uint32_t);
void OpPopa(struct Machine *, uint32_t);
void OpCallf(struct Machine *, uint32_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -21,9 +21,11 @@
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/sigaction-linux.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
@ -41,10 +43,14 @@
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/lock.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/rusage.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/so.h"
@ -52,6 +58,7 @@
#include "libc/sysv/consts/sol.h"
#include "libc/sysv/consts/tcp.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/consts/w.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/time.h"
@ -67,6 +74,14 @@
#define AT_FDCWD_LINUX -100
#define TIOCGWINSZ_LINUX 0x5413
#define TCGETS_LINUX 0x5401
#define TCSETS_LINUX 0x5402
#define TCSETSW_LINUX 0x5403
#define TCSETSF_LINUX 0x5404
#define ISIG_LINUX 0b0000000000000001
#define ICANON_LINUX 0b0000000000000010
#define ECHO_LINUX 0b0000000000001000
#define OPOST_LINUX 0b0000000000000001
#define POINTER(x) ((void *)(intptr_t)(x))
#define UNPOINTER(x) ((int64_t)(intptr_t)(x))
@ -322,8 +337,8 @@ static unsigned XlatOpenFlags(unsigned flags) {
return res;
}
static int XlatFcntlCmd(int cmd) {
switch (cmd) {
static int XlatFcntlCmd(int x) {
switch (x) {
XLAT(1, F_GETFD);
XLAT(2, F_SETFD);
XLAT(3, F_GETFL);
@ -333,8 +348,8 @@ static int XlatFcntlCmd(int cmd) {
}
}
static int XlatFcntlArg(int arg) {
switch (arg) {
static int XlatFcntlArg(int x) {
switch (x) {
XLAT(0, 0);
XLAT(1, FD_CLOEXEC);
default:
@ -342,6 +357,61 @@ static int XlatFcntlArg(int arg) {
}
}
static int XlatAdvice(int x) {
switch (x) {
XLAT(0, MADV_NORMAL);
XLAT(1, MADV_RANDOM);
XLAT(2, MADV_SEQUENTIAL);
XLAT(3, MADV_WILLNEED);
XLAT(4, MADV_DONTNEED);
XLAT(8, MADV_FREE);
XLAT(12, MADV_MERGEABLE);
default:
return einval();
}
}
static int XlatLock(int x) {
unsigned res = 0;
if (x & 1) res |= LOCK_SH;
if (x & 2) res |= LOCK_EX;
if (x & 4) res |= LOCK_NB;
if (x & 8) res |= LOCK_UN;
return res;
}
static int XlatWait(int x) {
unsigned res = 0;
if (x & 1) res |= WNOHANG;
if (x & 2) res |= WUNTRACED;
if (x & 8) res |= WCONTINUED;
return res;
}
static int XlatRusage(int x) {
switch (x) {
XLAT(0, RUSAGE_SELF);
XLAT(-1, RUSAGE_CHILDREN);
XLAT(1, RUSAGE_THREAD);
default:
return einval();
}
}
static void *VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
uint64_t n) {
VirtualSend(m, dst, addr, n);
SetReadAddr(m, addr, n);
return dst;
}
static void *VirtualRecvWrite(struct Machine *m, int64_t addr, void *dst,
uint64_t n) {
VirtualRecv(m, addr, dst, n);
SetWriteAddr(m, addr, n);
return dst;
}
static struct sigaction *CoerceSigactionToCosmo(
struct sigaction *dst, const struct sigaction$linux *src) {
if (!src) return NULL;
@ -364,6 +434,25 @@ static struct sigaction$linux *CoerceSigactionToLinux(
return dst;
}
static int OpArchPrctl(struct Machine *m, int code, int64_t addr) {
switch (code) {
case ARCH_SET_GS:
Write64(m->gs, addr);
return 0;
case ARCH_SET_FS:
Write64(m->fs, addr);
return 0;
case ARCH_GET_GS:
VirtualRecvWrite(m, addr, m->gs, 8);
return 0;
case ARCH_GET_FS:
VirtualRecvWrite(m, addr, m->fs, 8);
return 0;
default:
return einval();
}
}
static int OpMprotect(struct Machine *m, int64_t addr, uint64_t len, int prot) {
return 0;
}
@ -373,6 +462,25 @@ static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
return enosys();
}
static int64_t OpBrk(struct Machine *m, int64_t addr) {
void *real;
if (addr && addr != m->brk) {
if (addr < m->brk) {
addr = ROUNDUP(addr, FRAMESIZE);
FreePml4t(m->cr3, addr, m->brk - addr, free, munmap);
m->brk = addr;
} else {
addr = ROUNDUP(addr, FRAMESIZE);
if ((real = mmap(NULL, addr - m->brk, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
CHECK_NE(-1, RegisterMemory(m, m->brk, real, addr - m->brk));
m->brk = addr;
}
}
}
return m->brk;
}
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
int flags, int fd, int64_t off) {
void *real;
@ -417,8 +525,7 @@ static struct iovec *GetDirectIov(struct Machine *m, int64_t addr, int *len) {
struct iovec *iov;
if (!__builtin_mul_overflow(sizeof(*iov), *len, &n) && n <= 0x7ffff000) {
if ((iov = malloc(n))) {
VirtualSend(m, iov, addr, n);
SetReadAddr(m, addr, n);
VirtualSendRead(m, iov, addr, n);
for (i = 0; i < *len; ++i) {
size = iov[i].iov_len;
if ((iov[i].iov_base = GetDirectBuf(
@ -544,16 +651,14 @@ static int OpAccept4(struct Machine *m, int fd, int64_t addraddr,
uint8_t b[4];
uint32_t addrsize;
if ((fd = XlatFd(m, fd)) == -1) return -1;
VirtualSend(m, b, addrsizeaddr, 4);
SetReadAddr(m, addrsizeaddr, 4);
VirtualSendRead(m, b, addrsizeaddr, 4);
addrsize = Read32(b);
if (!(addr = malloc(addrsize))) return -1;
if ((i = rc = MachineFdAdd(&m->fds)) != -1) {
if ((rc = accept4(fd, addr, &addrsize, XlatSocketFlags(flags))) != -1) {
Write32(b, addrsize);
VirtualRecv(m, addrsizeaddr, b, 4);
VirtualRecv(m, addraddr, addr, addrsize);
SetWriteAddr(m, addraddr, addrsize);
VirtualRecvWrite(m, addraddr, addr, addrsize);
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = rc;
rc = i;
@ -572,8 +677,7 @@ static int OpConnectBind(struct Machine *m, int fd, intptr_t addraddr,
void *addr;
if ((fd = XlatFd(m, fd)) == -1) return -1;
if (!(addr = malloc(addrsize))) return -1;
VirtualSend(m, addr, addraddr, addrsize);
SetReadAddr(m, addraddr, addrsize);
VirtualSendRead(m, addr, addraddr, addrsize);
rc = impl(fd, addr, addrsize);
free(addr);
return rc;
@ -597,8 +701,7 @@ static int OpSetsockopt(struct Machine *m, int fd, int level, int optname,
if ((optname = XlatSocketOptname(optname)) == -1) return -1;
if ((fd = XlatFd(m, fd)) == -1) return -1;
if (!(optval = malloc(optvalsize))) return -1;
VirtualSend(m, optval, optvaladdr, optvalsize);
SetReadAddr(m, optvaladdr, optvalsize);
VirtualSendRead(m, optval, optvaladdr, optvalsize);
rc = setsockopt(fd, level, optname, optval, optvalsize);
free(optval);
return rc;
@ -626,17 +729,63 @@ static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
return rc;
}
static int OpIoctl(struct Machine *m, int fd, uint64_t request,
int64_t memaddr) {
static int IoctlTiocgwinsz(struct Machine *m, int fd, int64_t addr,
int (*fn)(int, uint64_t, void *)) {
int rc;
struct winsize ws;
if ((rc = fn(fd, TIOCGWINSZ, &ws)) != -1) {
VirtualRecvWrite(m, addr, &ws, sizeof(ws));
}
return rc;
}
static int IoctlTcgets(struct Machine *m, int fd, int64_t addr,
int (*fn)(int, uint64_t, void *)) {
int rc;
struct termios tio, tio2;
if ((rc = fn(fd, TCGETS, &tio)) != -1) {
memcpy(&tio2, &tio, sizeof(tio));
tio2.c_iflag = 0;
if (tio.c_iflag & ISIG) tio2.c_iflag |= ISIG_LINUX;
if (tio.c_iflag & ICANON) tio2.c_iflag |= ICANON_LINUX;
if (tio.c_iflag & ECHO) tio2.c_iflag |= ECHO_LINUX;
tio2.c_oflag = 0;
if (tio.c_oflag & OPOST) tio2.c_oflag |= OPOST_LINUX;
VirtualRecvWrite(m, addr, &tio2, sizeof(tio2));
}
return rc;
}
static int IoctlTcsets(struct Machine *m, int fd, int64_t request, int64_t addr,
int (*fn)(int, uint64_t, void *)) {
struct termios tio, tio2;
VirtualSendRead(m, &tio, addr, sizeof(tio));
memcpy(&tio2, &tio, sizeof(tio));
tio2.c_iflag = 0;
if (tio.c_iflag & ISIG_LINUX) tio2.c_iflag |= ISIG;
if (tio.c_iflag & ICANON_LINUX) tio2.c_iflag |= ICANON;
if (tio.c_iflag & ECHO_LINUX) tio2.c_iflag |= ECHO;
tio2.c_oflag = 0;
if (tio.c_oflag & OPOST_LINUX) tio2.c_oflag |= OPOST;
return fn(fd, request, &tio2);
}
static int OpIoctl(struct Machine *m, int fd, uint64_t request, int64_t addr) {
int (*fn)(int, uint64_t, void *);
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
fn = m->fds.p[fd].cb->ioctl;
fd = m->fds.p[fd].fd;
switch (request) {
case TIOCGWINSZ_LINUX:
rc = (m->fds.p[fd].cb->ioctl)(m->fds.p[fd].fd, TIOCGWINSZ, &ws);
VirtualRecv(m, memaddr, &ws, sizeof(ws));
SetWriteAddr(m, memaddr, sizeof(ws));
return rc;
return IoctlTiocgwinsz(m, fd, addr, fn);
case TCGETS_LINUX:
return IoctlTcgets(m, fd, addr, fn);
case TCSETS_LINUX:
return IoctlTcsets(m, fd, TCSETS, addr, fn);
case TCSETSW_LINUX:
return IoctlTcsets(m, fd, TCSETSW, addr, fn);
case TCSETSF_LINUX:
return IoctlTcsets(m, fd, TCSETSF, addr, fn);
default:
return einval();
}
@ -763,6 +912,19 @@ static int OpFcntl(struct Machine *m, int fd, int cmd, int arg) {
return fcntl(fd, cmd, arg);
}
static int OpFadvise(struct Machine *m, int fd, uint64_t offset, uint64_t len,
int advice) {
if ((fd = XlatFd(m, fd)) == -1) return -1;
if ((advice = XlatAdvice(advice)) == -1) return -1;
return fadvise(fd, offset, len, advice);
}
static int OpFlock(struct Machine *m, int fd, int lock) {
if ((fd = XlatFd(m, fd)) == -1) return -1;
if ((lock = XlatLock(lock)) == -1) return -1;
return flock(fd, lock);
}
static int OpChdir(struct Machine *m, int64_t path) {
return chdir(LoadStr(m, path));
}
@ -813,6 +975,37 @@ static int OpExecve(struct Machine *m, int64_t programaddr, int64_t argvaddr,
return enosys();
}
static int OpWait4(struct Machine *m, int pid, int64_t opt_out_wstatus_addr,
int options, int64_t opt_out_rusage_addr) {
int rc;
int32_t wstatus;
struct rusage rusage;
if ((options = XlatWait(options)) == -1) return -1;
if ((rc = wait4(pid, &wstatus, options, &rusage)) != -1) {
if (opt_out_wstatus_addr) {
VirtualRecvWrite(m, opt_out_wstatus_addr, &wstatus, sizeof(wstatus));
}
if (opt_out_rusage_addr) {
VirtualRecvWrite(m, opt_out_rusage_addr, &rusage, sizeof(rusage));
}
}
return rc;
}
static int OpGetrusage(struct Machine *m, int resource, int64_t rusageaddr) {
int rc;
struct rusage rusage;
if ((resource = XlatRusage(resource)) == -1) return -1;
if ((rc = getrusage(resource, &rusage)) != -1) {
VirtualRecvWrite(m, rusageaddr, &rusage, sizeof(rusage));
}
return rc;
}
static int OpGetrlimit(struct Machine *m, int resource, int64_t rlimitaddr) {
return enosys();
}
static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
size_t n;
char *buf;
@ -821,8 +1014,7 @@ static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
if (!(buf = malloc(size))) return enomem();
if ((getcwd)(buf, size)) {
n = strlen(buf);
VirtualRecv(m, bufaddr, buf, n);
SetWriteAddr(m, bufaddr, n);
VirtualRecvWrite(m, bufaddr, buf, n);
res = bufaddr;
} else {
res = -1;
@ -904,8 +1096,7 @@ static int OpPoll(struct Machine *m, int64_t fdsaddr, uint64_t nfds,
struct pollfd *fds;
if (!__builtin_mul_overflow(sizeof(*fds), nfds, &n) && n <= 0x7ffff000) {
if ((fds = malloc(n))) {
VirtualSend(m, fds, fdsaddr, n);
SetReadAddr(m, fdsaddr, n);
VirtualSendRead(m, fds, fdsaddr, n);
rc = poll(fds, nfds, timeout_ms);
free(fds);
return rc;
@ -924,17 +1115,53 @@ static int OpSigprocmask(struct Machine *m, int how, int64_t setaddr,
if (setaddr) {
set = &ss;
memset(set, 0, sizeof(ss));
VirtualSend(m, set, setaddr, 8);
VirtualSendRead(m, set, setaddr, 8);
} else {
set = NULL;
}
if ((rc = sigprocmask(XlatSig(how), set, &oldset)) != -1) {
if (setaddr) VirtualRecv(m, setaddr, set, 8);
if (oldsetaddr) VirtualRecv(m, oldsetaddr, &oldset, 8);
if (setaddr) VirtualRecvWrite(m, setaddr, set, 8);
if (oldsetaddr) VirtualRecvWrite(m, oldsetaddr, &oldset, 8);
}
return rc;
}
static int OpGetPid(struct Machine *m) {
return getpid();
}
static int OpGetPpid(struct Machine *m) {
return getppid();
}
static int OpKill(struct Machine *m, int pid, int sig) {
return kill(pid, sig);
}
static int OpGetUid(struct Machine *m) {
return getuid();
}
static int OpGetGid(struct Machine *m) {
return getgid();
}
static int OpGetTid(struct Machine *m) {
return gettid();
}
static int OpSchedYield(struct Machine *m) {
return sched_yield();
}
static int OpAlarm(struct Machine *m, unsigned seconds) {
return alarm(seconds);
}
static int OpPause(struct Machine *m) {
return pause();
}
static int DoOpen(struct Machine *m, int64_t path, int flags, int mode) {
return OpOpenat(m, AT_FDCWD_LINUX, path, flags, mode);
}
@ -983,6 +1210,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x01A, OpMsync(m, di, si, dx));
SYSCALL(0x00A, OpMprotect(m, di, si, dx));
SYSCALL(0x00B, OpMunmap(m, di, si));
SYSCALL(0x00C, OpBrk(m, di));
SYSCALL(0x00D, OpSigaction(m, di, si, dx));
SYSCALL(0x00E, OpSigprocmask(m, di, si, dx));
SYSCALL(0x010, OpIoctl(m, di, si, dx));
@ -993,16 +1221,16 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x015, DoAccess(m, di, si));
SYSCALL(0x016, OpPipe(m, di));
SYSCALL(0x017, select(di, P(si), P(dx), P(r0), P(r8)));
SYSCALL(0x018, sched_yield());
SYSCALL(0x018, OpSchedYield(m));
SYSCALL(0x01C, OpMadvise(m, di, si, dx));
SYSCALL(0x020, OpDup(m, di));
SYSCALL(0x021, OpDup2(m, di, si));
SYSCALL(0x022, pause());
SYSCALL(0x022, OpPause(m));
SYSCALL(0x023, OpNanosleep(m, di, si));
SYSCALL(0x024, getitimer(di, PNN(si)));
SYSCALL(0x025, alarm(di));
SYSCALL(0x025, OpAlarm(m, di));
SYSCALL(0x026, setitimer(di, PNN(si), P(dx)));
SYSCALL(0x027, getpid());
SYSCALL(0x027, OpGetPid(m));
SYSCALL(0x028, sendfile(di, si, P(dx), r0));
SYSCALL(0x029, OpSocket(m, di, si, dx));
SYSCALL(0x02A, OpConnect(m, di, si, dx));
@ -1018,11 +1246,11 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x037, getsockopt(di, si, dx, PNN(r0), PNN(r8)));
SYSCALL(0x039, OpFork(m));
SYSCALL(0x03B, OpExecve(m, di, si, dx));
SYSCALL(0x03D, wait4(di, P(si), dx, P(r0)));
SYSCALL(0x03E, kill(di, si));
SYSCALL(0x03D, OpWait4(m, di, si, dx, r0));
SYSCALL(0x03E, OpKill(m, di, si));
SYSCALL(0x03F, uname(P(di)));
SYSCALL(0x048, OpFcntl(m, di, si, dx));
SYSCALL(0x049, flock(di, si));
SYSCALL(0x049, OpFlock(m, di, si));
SYSCALL(0x04A, OpFsync(m, di));
SYSCALL(0x04B, OpFdatasync(m, di));
SYSCALL(0x04C, OpTruncate(m, di, si));
@ -1039,13 +1267,13 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x05A, OpChmod(m, di, si));
SYSCALL(0x05B, OpFchmod(m, di, si));
SYSCALL(0x060, OpGettimeofday(m, di, si));
SYSCALL(0x061, getrlimit(di, P(si)));
SYSCALL(0x062, getrusage(di, P(si)));
SYSCALL(0x061, OpGetrlimit(m, di, si));
SYSCALL(0x062, OpGetrusage(m, di, si));
SYSCALL(0x063, sysinfo(PNN(di)));
SYSCALL(0x064, times(PNN(di)));
SYSCALL(0x066, getuid());
SYSCALL(0x068, getgid());
SYSCALL(0x06E, getppid());
SYSCALL(0x066, OpGetUid(m));
SYSCALL(0x068, OpGetGid(m));
SYSCALL(0x06E, OpGetPpid(m));
SYSCALL(0x075, setresuid(di, si, dx));
SYSCALL(0x077, setresgid(di, si, dx));
SYSCALL(0x082, OpSigsuspend(m, di));
@ -1055,10 +1283,10 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x0A0, setrlimit(di, P(si)));
SYSCALL(0x084, utime(PNN(di), PNN(si)));
SYSCALL(0x0EB, utimes(P(di), P(si)));
SYSCALL(0x09E, arch_prctl(di, si));
SYSCALL(0x0BA, gettid());
SYSCALL(0x09E, OpArchPrctl(m, di, si));
SYSCALL(0x0BA, OpGetTid(m));
SYSCALL(0x0CB, sched_setaffinity(di, si, P(dx)));
SYSCALL(0x0DD, fadvise(di, si, dx, r0));
SYSCALL(0x0DD, OpFadvise(m, di, si, dx, r0));
SYSCALL(0x0E4, OpClockGettime(m, di, si));
SYSCALL(0x101, OpOpenat(m, di, si, dx, r0));
SYSCALL(0x102, mkdirat(XlatAfd(m, di), P(si), dx));
@ -1075,7 +1303,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
CASE(0xE7, HaltMachine(m, di | 0x100));
default:
DEBUGF("missing syscall %03x", ax);
/* LOGF("missing syscall 0x%03x", ax); */
ax = enosys();
break;
}

View file

@ -49,7 +49,6 @@ void ThrowProtectionFault(struct Machine *m) {
}
void OpUd(struct Machine *m, uint32_t rde) {
DebugBreak();
m->ip -= m->xedd->length;
HaltMachine(m, kMachineUndefinedInstruction);
}

View file

@ -33,13 +33,9 @@ void OpPause(struct Machine *m, uint32_t rde) {
*/
void OpRdtsc(struct Machine *m, uint32_t rde) {
uint64_t c;
#ifdef __x86_64__
c = rdtsc();
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
c = ts.tv_sec * 1000000000 + ts.tv_nsec;
#endif
Write64(m->ax, (c >> 000) & 0xffffffff);
Write64(m->dx, (c >> 040) & 0xffffffff);
}
@ -50,5 +46,5 @@ void OpRdtscp(struct Machine *m, uint32_t rde) {
core = 0;
node = 0;
tscaux = (node & 0xfff) << 12 | (core & 0xfff);
Write64(m->ax, tscaux & 0xffffffff);
Write64(m->cx, tscaux & 0xffffffff);
}

145
tool/build/lisp.c Normal file
View file

@ -0,0 +1,145 @@
/*-*- 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/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#define T short
#define CONS 0
#define ATOM 1
#define INTEGER 2
#define NIL OBJECT(CONS, 0)
#define TYPE(x) ((x)&3)
#define VALUE(x) ((x) >> 2)
#define OBJECT(t, v) ((v) << 2 | (t))
static T Mi, Si;
static T M[2048];
static char S[2048];
static noreturn void Die(void) {
abort();
}
static int Parse(const char *s) {
int x, j;
for (;;) {
switch (*s & 0xff) {
case ' ':
case '\t':
case '\r':
case '\n':
case '\v':
++s;
break;
case 'A' ... 'Z':
x = Si;
do {
S[Si++] = *s++;
} while ('A' <= *s && *s <= 'Z');
S[Si++] = 0;
M[++Mi] = OBJECT(ATOM, x);
return Mi;
case '0' ... '9':
x = 0;
do {
x *= 10;
x += *s++ - '0';
} while ('0' <= *s && *s <= '9');
M[++Mi] = OBJECT(INTEGER, x);
return Mi;
default:
Die();
}
}
}
static int PrintChar(int c) {
return putc(c, stdout);
}
static void PrintString(const char *s) {
while (*s) PrintChar(*s++);
}
static void PrintInteger(int x) {
int q, r;
q = x / 10;
r = x % 10;
if (q) PrintInteger(q);
PrintChar('0' + r);
}
static void PrintObject(int i) {
int j, x;
switch (TYPE(M[i])) {
case CONS:
if ((i = VALUE(M[i]))) {
PrintChar('(');
PrintObject(i);
for (;;) {
if (TYPE(M[i + 1]) == CONS) {
if (!(i = VALUE(M[i + 1]))) break;
PrintChar(' ');
PrintObject(i);
} else {
PrintString(" . ");
PrintObject(i + 1);
break;
}
}
PrintChar(')');
} else {
PrintString("NIL");
}
break;
case ATOM:
for (j = VALUE(M[i]); S[j]; ++j) {
PrintChar(S[j]);
}
break;
case INTEGER:
PrintInteger(VALUE(M[i]));
break;
default:
unreachable;
}
}
static void Print(int i) {
PrintObject(i);
PrintChar('\n');
}
int main(int argc, char *argv[]) {
int i;
M[1] = OBJECT(CONS, 2);
M[2] = OBJECT(INTEGER, 123);
M[3] = OBJECT(CONS, 4);
M[4] = OBJECT(INTEGER, 456);
M[5] = OBJECT(CONS, 6);
M[6] = OBJECT(INTEGER, 789);
M[7] = NIL;
Print(1);
return 0;
}

View file

@ -25,6 +25,7 @@
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
@ -39,28 +40,42 @@
#include "libc/str/str.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/getopt/getopt.h"
#define MAX_READ FRAMESIZE
/**
* @fileoverview Make dependency generator.
*
* This program generates Makefile code saying which sources include
* which headers, thus improving build invalidation.
* This generates Makefile code for source -> header dependencies.
*
* 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.
* Includes look like this:
*
* - #include "root/of/repository/foo.h"
* - .include "root/of/repository/foo.inc"
*
* They do not look like this:
*
* - #include "foo.h"
* - # include "foo.h"
* - #include "foo.h"
*
* Only the first 64kb of each source file is considered.
*/
static const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"};
static alignas(16) const char kIncludePrefix[] = "include \"";
alignas(16) const char kIncludePrefix[] = "include \"";
static const char *const kModelessPackages[] = {
"libc/nt/",
"libc/stubs/",
"libc/sysv/",
const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"};
const char *const kIgnorePrefixes[] = {
#if 0
"libc/sysv/consts/", "libc/sysv/calls/", "libc/nt/kernel32/",
"libc/nt/KernelBase/", "libc/nt/advapi32/", "libc/nt/gdi32/",
"libc/nt/ntdll/", "libc/nt/user32/", "libc/nt/shell32/",
#endif
};
struct Strings {
@ -69,14 +84,14 @@ struct Strings {
};
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 */
unsigned hash; /* 0 means empty w/ triangle probe */
unsigned name; /* strings.p[name] w/ interning */
unsigned id; /* rehashing changes indexes */
};
struct Edge {
int32_t from; /* sources.p[from.id] */
int32_t to; /* sources.p[to.id] */
unsigned from; /* sources.p[from.id] */
unsigned to; /* sources.p[to.id] */
};
struct Sources {
@ -89,27 +104,42 @@ struct Edges {
struct Edge *p;
};
int g_sourceid;
struct Strings strings;
struct Sources sources;
struct Edges edges;
const char *buildroot;
int *visited;
char *out;
FILE *fout;
int *visited;
unsigned counter;
struct Edges edges;
struct Strings strings;
struct Sources sources;
const char *buildroot;
static int CompareSourcesById(struct Source *a, struct Source *b) {
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) {
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) {
unsigned Hash(const void *s, size_t l) {
return max(1, crc32c(0, s, l));
}
unsigned FindFirstFromEdge(unsigned id) {
unsigned m, l, r;
l = 0;
r = edges.i;
while (l < r) {
m = (l + r) >> 1;
if (edges.p[m].from < id) {
l = m + 1;
} else {
r = m;
}
}
return l;
}
void Crunch(void) {
size_t i, j;
for (i = 0, j = 0; j < sources.n; ++j) {
@ -140,9 +170,9 @@ void Rehash(void) {
free(old.p);
}
uint32_t GetSourceId(const char *name, size_t len) {
unsigned GetSourceId(const char *name, size_t len) {
size_t i, step;
uint32_t hash;
unsigned hash;
i = 0;
hash = Hash(name, len);
if (sources.n) {
@ -167,55 +197,73 @@ uint32_t GetSourceId(const char *name, size_t len) {
sources.p[i].hash = hash;
sources.p[i].name = CONCAT(&strings.p, &strings.i, &strings.n, name, len);
strings.p[strings.i++] = '\0';
return (sources.p[i].id = g_sourceid++);
return (sources.p[i].id = counter++);
}
bool ShouldSkipSource(const char *src) {
unsigned j;
for (j = 0; j < ARRAYLEN(kIgnorePrefixes); ++j) {
if (startswith(src, kIgnorePrefixes[j])) {
return true;
}
}
return false;
}
noreturn void OnMissingFile(const char *list, const char *src) {
DCHECK_EQ(ENOENT, errno, "%s", src);
/*
* This code helps GNU Make automatically fix itself when we
* delete a source file. It removes o/.../srcs.txt or
* o/.../hdrs.txt and exits nonzero. Since we use hyphen
* notation on mkdeps related rules, the build will
* automatically restart itself.
*/
fprintf(stderr, "%s %s...\n", "Refreshing", list);
unlink(list);
exit(1);
}
void LoadRelationships(int argc, char *argv[]) {
struct MappedFile mf;
const char *p, *pe;
size_t i, linecap = 0;
char *line = NULL;
int fd;
ssize_t rc;
bool skipme;
FILE *finpaths;
struct Edge edge;
char *line, *buf;
unsigned srcid, dependency;
size_t i, linecap, inclen, size;
const char *p, *pe, *src, *path, *pathend;
line = NULL;
linecap = 0;
inclen = strlen(kIncludePrefix);
buf = gc(xmemalign(PAGESIZE, PAGESIZE + MAX_READ + 16));
buf += PAGESIZE;
buf[-1] = '\n';
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;
src = chomp(line);
if (ShouldSkipSource(src)) continue;
srcid = GetSourceId(src, strlen(src));
if ((fd = open(src, O_RDONLY)) == -1) OnMissingFile(argv[i], src);
CHECK_NE(-1, (rc = read(fd, buf, MAX_READ)));
close(fd);
size = rc;
memset(buf + size, 0, 16);
for (p = buf, pe = p + size; p < pe; ++p) {
p = strstr(p, kIncludePrefix);
if (!p) break;
path = p + inclen;
pathend = memchr(path, '"', pe - path);
if (pathend && (p[-1] == '#' || p[-1] == '.') && p[-2] == '\n') {
dependency = GetSourceId(path, pathend - path);
edge.from = srcid;
edge.to = dependency;
append(&edges, &edge);
p = pathend;
}
}
CHECK_NE(-1, unmapfile(&mf));
}
CHECK_NE(-1, fclose(finpaths));
}
@ -258,60 +306,100 @@ const char *StripExt(const char *s) {
}
bool IsObjectSource(const char *name) {
for (size_t i = 0; i < ARRAYLEN(kSourceExts); ++i) {
int i;
for (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;
void Dive(unsigned id) {
int i;
for (i = FindFirstFromEdge(id); i < edges.i && edges.p[i].from == id; ++i) {
if (bts(visited, edges.p[i].to)) continue;
fputs(" \\\n\t", fout);
fputs(&strings.p[sources.p[dep].name], fout);
Dive(dep);
fputs(&strings.p[sources.p[edges.p[i].to].name], fout);
Dive(edges.p[i].to);
}
}
bool IsModeless(const char *path) {
size_t i;
for (i = 0; i < ARRAYLEN(kModelessPackages); ++i) {
if (startswith(path, kModelessPackages[i])) return true;
size_t GetFileSizeOrZero(const char *path) {
struct stat st;
st.st_size = 0;
stat(path, &st);
return st.st_size;
}
bool FilesHaveSameContent(const char *path1, const char *path2) {
bool r;
int c1, c2;
size_t s1, s2;
FILE *f1, *f2;
s1 = GetFileSizeOrZero(path1);
s2 = GetFileSizeOrZero(path2);
if (s1 == s2) {
r = true;
if (s1) {
CHECK_NOTNULL((f1 = fopen(path1, "r")));
CHECK_NOTNULL((f2 = fopen(path2, "r")));
for (;;) {
c1 = getc(f1);
c2 = getc(f2);
if (c1 != c2) {
r = false;
break;
}
if (c1 == -1) {
break;
}
}
CHECK_NE(-1, fclose(f2));
CHECK_NE(-1, fclose(f1));
}
} else {
r = false;
}
return false;
return r;
}
int main(int argc, char *argv[]) {
char *tp;
bool needprefix;
size_t i, bitmaplen;
const char *path, *prefix;
showcrashreports();
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")));
tp = !fileexists(out) || isregularfile(out) ? xasprintf("%s.tmp", out) : NULL;
CHECK_NOTNULL((fout = fopen(tp ? tp : out, "w")));
LoadRelationships(argc, argv);
Crunch();
size_t bitmaplen = roundup((sources.i + 8) / 8, 4);
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];
for (i = 0; i < sources.i; ++i) {
path = &strings.p[sources.p[i].name];
if (!IsObjectSource(path)) continue;
bool needprefix = !startswith(path, "o/");
const char *prefix = !needprefix ? "" : IsModeless(path) ? "o/" : buildroot;
needprefix = !startswith(path, "o/");
prefix = !needprefix ? "" : 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);
CHECK_NE(-1, fclose(fout));
if (tp) {
/* prevent gnu make from restarting unless necessary */
if (!FilesHaveSameContent(tp, out)) {
CHECK_NE(-1, rename(tp, out));
} else {
CHECK_NE(-1, unlink(tp));
}
}
free_s(&strings.p);
free_s(&sources.p);
free_s(&edges.p);
free_s(&visited);
free_s(&tmp);
free_s(&tp);
return 0;
}

View file

@ -352,7 +352,8 @@ void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot,
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(iself64binary(obj->elf, obj->size), "path=%`'s",
&pkg->strings.p[obj->path]);
CHECK_NOTNULL((obj->strs = getelfstringtable(obj->elf, obj->size)));
CHECK_NOTNULL(
(obj->syms = getelfsymboltable(obj->elf, obj->size, &obj->symcount)));

View file

@ -36,7 +36,6 @@ int main(int argc, char *argv[]) {
int rc;
struct Elf elf;
const char *codepath;
showcrashreports();
codepath = argv[1];
if (argc < 2) {
fputs("Usage: ", stderr);

900
tool/calc/calc.c Normal file
View file

@ -0,0 +1,900 @@
/*-*- 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/conv/conv.h"
#include "libc/errno.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "o/tool/calc/calc.c.inc"
#include "o/tool/calc/calc.h.inc"
#include "tool/calc/calc.h"
/**
* make -j8 o//tool/calc
* rlwrap -A -H ~/.calc -f tool/calc/calc.lst -e\( o//tool/calc/calc.com
* @see https://github.com/hanslub42/rlwrap
*/
static jmp_buf jb;
static int g_line;
static int g_column;
static const char *g_file;
static yyParser g_parser[1];
noreturn static void Error(const char *msg) {
fprintf(stderr, "%s:%d:%d: %s\n", g_file, g_line, g_column, msg);
longjmp(jb, 1);
}
noreturn static void SyntaxError(void) {
Error("SYNTAX ERROR");
}
noreturn static void LexError(void) {
Error("LEX ERROR");
}
noreturn static void MissingArgumentError(void) {
Error("MISSING ARGUMENT");
}
noreturn static void MissingFunctionError(void) {
Error("MISSING FUNCTION");
}
noreturn static void SyscallError(const char *name) {
fprintf(stderr, "ERROR: %s[%s]: %d\n", name, g_file, errno);
exit(1);
}
static void NumbersFree(struct Numbers *n) {
if (n) {
NumbersFree(n->n);
free(n);
}
}
static struct Numbers *NumbersAppend(struct Numbers *n, long double x) {
struct Numbers *a;
a = malloc(sizeof(struct Numbers));
a->n = n;
a->x = x;
return a;
}
static long double ParseNumber(struct Token t) {
char *ep;
ep = t.s + t.n;
if (t.s[0] == '0') {
return strtoumax(t.s, &ep, 0);
} else {
return strtod(t.s, &ep);
}
}
static long double FnAtan2(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return atan2l(a->n->x, a->x);
}
static long double FnLdexp(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return ldexpl(a->n->x, a->x);
}
static long double FnCopysign(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return copysignl(a->n->x, a->x);
}
static long double FnFmax(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return fmaxl(a->n->x, a->x);
}
static long double FnFmin(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return fminl(a->n->x, a->x);
}
static long double FnFmod(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return fmodl(a->n->x, a->x);
}
static long double FnHypot(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return hypotl(a->n->x, a->x);
}
static long double FnPowi(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return powil(a->n->x, a->x);
}
static long double FnPow(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return powl(a->n->x, a->x);
}
static long double FnScalb(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return scalbl(a->n->x, a->x);
}
static long double FnIsgreater(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return isgreater(a->n->x, a->x);
}
static long double FnRemainder(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return remainderl(a->n->x, a->x);
}
static long double FnIsgreaterequal(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return isgreaterequal(a->n->x, a->x);
}
static long double FnIsless(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return isless(a->n->x, a->x);
}
static long double FnIslessequal(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return islessequal(a->n->x, a->x);
}
static long double FnIslessgreater(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return islessgreater(a->n->x, a->x);
}
static long double FnIsunordered(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return isunordered(a->n->x, a->x);
}
static long double FnRounddown(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return ROUNDDOWN((int128_t)a->n->x, (int128_t)a->x);
}
static long double FnRoundup(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return ROUNDUP((int128_t)a->n->x, (int128_t)a->x);
}
static long double FnAcos(struct Numbers *a) {
if (!a) MissingArgumentError();
return acosl(a->x);
}
static long double FnAsin(struct Numbers *a) {
if (!a) MissingArgumentError();
return asinl(a->x);
}
static long double FnAtan(struct Numbers *a) {
if (!a) MissingArgumentError();
return atanl(a->x);
}
static long double FnCbrt(struct Numbers *a) {
if (!a) MissingArgumentError();
return cbrtl(a->x);
}
static long double FnCeil(struct Numbers *a) {
if (!a) MissingArgumentError();
return ceill(a->x);
}
static long double FnCos(struct Numbers *a) {
if (!a) MissingArgumentError();
return cosl(a->x);
}
static long double FnExp10(struct Numbers *a) {
if (!a) MissingArgumentError();
return exp10l(a->x);
}
static long double FnExp2(struct Numbers *a) {
if (!a) MissingArgumentError();
return exp2l(a->x);
}
static long double FnExp(struct Numbers *a) {
if (!a) MissingArgumentError();
return expl(a->x);
}
static long double FnExpm1(struct Numbers *a) {
if (!a) MissingArgumentError();
return expm1l(a->x);
}
static long double FnFabs(struct Numbers *a) {
if (!a) MissingArgumentError();
return fabsl(a->x);
}
static long double FnFloor(struct Numbers *a) {
if (!a) MissingArgumentError();
return floorl(a->x);
}
static long double FnIlogb(struct Numbers *a) {
if (!a) MissingArgumentError();
return ilogbl(a->x);
}
static long double FnLog10(struct Numbers *a) {
if (!a) MissingArgumentError();
return log10l(a->x);
}
static long double FnLog1p(struct Numbers *a) {
if (!a) MissingArgumentError();
return log1pl(a->x);
}
static long double FnLog2(struct Numbers *a) {
if (!a) MissingArgumentError();
return log2l(a->x);
}
static long double FnLogb(struct Numbers *a) {
if (!a) MissingArgumentError();
return logbl(a->x);
}
static long double FnLog(struct Numbers *a) {
if (!a) MissingArgumentError();
return logl(a->x);
}
static long double FnLrint(struct Numbers *a) {
if (!a) MissingArgumentError();
return lrintl(a->x);
}
static long double FnLround(struct Numbers *a) {
if (!a) MissingArgumentError();
return lroundl(a->x);
}
static long double FnNearbyint(struct Numbers *a) {
if (!a) MissingArgumentError();
return nearbyintl(a->x);
}
static long double FnRint(struct Numbers *a) {
if (!a) MissingArgumentError();
return rintl(a->x);
}
static long double FnRound(struct Numbers *a) {
if (!a) MissingArgumentError();
return roundl(a->x);
}
static long double FnSignificand(struct Numbers *a) {
if (!a) MissingArgumentError();
return significandl(a->x);
}
static long double FnSin(struct Numbers *a) {
if (!a) MissingArgumentError();
return sinl(a->x);
}
static long double FnSqrt(struct Numbers *a) {
if (!a) MissingArgumentError();
return sqrtl(a->x);
}
static long double FnTan(struct Numbers *a) {
if (!a) MissingArgumentError();
return tanl(a->x);
}
static long double FnTrunc(struct Numbers *a) {
if (!a) MissingArgumentError();
return truncl(a->x);
}
static long double FnIsinf(struct Numbers *a) {
if (!a) MissingArgumentError();
return isinf(a->x);
}
static long double FnIsnan(struct Numbers *a) {
if (!a) MissingArgumentError();
return isnan(a->x);
}
static long double FnIsfinite(struct Numbers *a) {
if (!a) MissingArgumentError();
return isfinite(a->x);
}
static long double FnIsnormal(struct Numbers *a) {
if (!a) MissingArgumentError();
return isnormal(a->x);
}
static long double FnSignbit(struct Numbers *a) {
if (!a) MissingArgumentError();
return signbit(a->x);
}
static long double FnFpclassify(struct Numbers *a) {
if (!a) MissingArgumentError();
return fpclassify(a->x);
}
static long double FnBsr(struct Numbers *a) {
if (!a) MissingArgumentError();
return bsr(a->x);
}
static long double FnBsfl(struct Numbers *a) {
if (!a) MissingArgumentError();
return bsfl(a->x);
}
static long double FnFfs(struct Numbers *a) {
if (!a) MissingArgumentError();
return ffs(a->x);
}
static long double FnFfsl(struct Numbers *a) {
if (!a) MissingArgumentError();
return ffsl(a->x);
}
static long double FnGray(struct Numbers *a) {
if (!a) MissingArgumentError();
return gray(a->x);
}
static long double FnUngray(struct Numbers *a) {
if (!a) MissingArgumentError();
return ungray(a->x);
}
static long double FnRounddown2pow(struct Numbers *a) {
if (!a) MissingArgumentError();
return rounddown2pow(a->x);
}
static long double FnRoundup2pow(struct Numbers *a) {
if (!a) MissingArgumentError();
return roundup2pow(a->x);
}
static long double FnRoundup2log(struct Numbers *a) {
if (!a) MissingArgumentError();
return roundup2log(a->x);
}
static long double FnBitreverse8(struct Numbers *a) {
if (!a) MissingArgumentError();
return bitreverse8(a->x);
}
static long double FnBitreverse16(struct Numbers *a) {
if (!a) MissingArgumentError();
return bitreverse16(a->x);
}
static long double FnBitreverse32(struct Numbers *a) {
if (!a) MissingArgumentError();
return bitreverse32(a->x);
}
static long double FnBitreverse64(struct Numbers *a) {
if (!a) MissingArgumentError();
return bitreverse64(a->x);
}
static int8_t sarb(int8_t x, uint8_t y) {
return x >> (y & 7);
}
static int16_t sarw(int16_t x, uint8_t y) {
return x >> (y & 15);
}
static int32_t sarl(int32_t x, uint8_t y) {
return x >> (y & 31);
}
static int64_t sarq(int64_t x, uint8_t y) {
return x >> (y & 63);
}
static long double FnSarb(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return sarb(a->n->x, a->x);
}
static long double FnSarw(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return sarw(a->n->x, a->x);
}
static long double FnSarl(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return sarl(a->n->x, a->x);
}
static long double FnSarq(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return sarq(a->n->x, a->x);
}
static long double FnSar(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return sarq(a->n->x, a->x);
}
static uint8_t rorb(uint8_t x, uint8_t y) {
return x >> (y & 7) | x << (8 - (y & 7));
}
static uint16_t rorw(uint16_t x, uint8_t y) {
return x >> (y & 15) | x << (16 - (y & 15));
}
static uint32_t rorl(uint32_t x, uint8_t y) {
return x >> (y & 31) | x << (32 - (y & 31));
}
static uint64_t rorq(uint64_t x, uint8_t y) {
return x >> (y & 63) | x << (64 - (y & 63));
}
static long double FnRorb(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rorb(a->n->x, a->x);
}
static long double FnRorw(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rorw(a->n->x, a->x);
}
static long double FnRorl(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rorl(a->n->x, a->x);
}
static long double FnRorq(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rorq(a->n->x, a->x);
}
static long double FnRor(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rorq(a->n->x, a->x);
}
static uint8_t rolb(uint8_t x, uint8_t y) {
return x << (y & 7) | x >> (8 - (y & 7));
}
static uint16_t rolw(uint16_t x, uint8_t y) {
return x << (y & 15) | x >> (16 - (y & 15));
}
static uint32_t roll(uint32_t x, uint8_t y) {
return x << (y & 31) | x >> (32 - (y & 31));
}
static uint64_t rolq(uint64_t x, uint8_t y) {
return x << (y & 63) | x >> (64 - (y & 63));
}
static long double FnRolb(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rolb(a->n->x, a->x);
}
static long double FnRolw(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rolw(a->n->x, a->x);
}
static long double FnRoll(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return roll(a->n->x, a->x);
}
static long double FnRolq(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rolq(a->n->x, a->x);
}
static long double FnRol(struct Numbers *a) {
if (!a || !a->n) MissingArgumentError();
return rolq(a->n->x, a->x);
}
static long double FnTime(struct Numbers *a) {
return nowl();
}
static long double FnBin(struct Numbers *a) {
if (!a) MissingArgumentError();
printf("0b%jb\n", (uint128_t)a->x);
return 0;
}
static long double FnOct(struct Numbers *a) {
if (!a) MissingArgumentError();
printf("0%jo\n", (uint128_t)a->x);
return 0;
}
static long double FnHex(struct Numbers *a) {
if (!a) MissingArgumentError();
printf("0x%jx\n", (uint128_t)a->x);
return 0;
}
static void PrintNumber(long double x) {
char b[32];
g_fmt(b, x);
fputs(b, stdout);
}
static void Print(struct Numbers *a) {
if (a) {
Print(a->n);
if (a->n) fputc(' ', stdout);
PrintNumber(a->x);
}
}
static long double FnPrint(struct Numbers *a) {
Print(a);
fputc('\n', stdout);
return 0;
}
static const struct Fn {
const char *s;
long double (*f)(struct Numbers *);
} kFunctions[] = {
{"abs", FnFabs},
{"acos", FnAcos},
{"asin", FnAsin},
{"atan", FnAtan},
{"atan2", FnAtan2},
{"bin", FnBin},
{"bitreverse16", FnBitreverse16},
{"bitreverse32", FnBitreverse32},
{"bitreverse64", FnBitreverse64},
{"bitreverse8", FnBitreverse8},
{"bsfl", FnBsfl},
{"bsfl", FnBsfl},
{"bsr", FnBsr},
{"bsr", FnBsr},
{"cbrt", FnCbrt},
{"ceil", FnCeil},
{"copysign", FnCopysign},
{"cos", FnCos},
{"exp", FnExp},
{"exp10", FnExp10},
{"exp2", FnExp2},
{"expm1", FnExpm1},
{"fabs", FnFabs},
{"ffs", FnFfs},
{"ffsl", FnFfsl},
{"floor", FnFloor},
{"fmax", FnFmax},
{"fmin", FnFmin},
{"fmod", FnFmod},
{"fpclassify", FnFpclassify},
{"gray", FnGray},
{"hex", FnHex},
{"hypot", FnHypot},
{"ilogb", FnIlogb},
{"isfinite", FnIsfinite},
{"isgreater", FnIsgreater},
{"isgreaterequal", FnIsgreaterequal},
{"isinf", FnIsinf},
{"isless", FnIsless},
{"islessequal", FnIslessequal},
{"islessgreater", FnIslessgreater},
{"isnan", FnIsnan},
{"isnormal", FnIsnormal},
{"isunordered", FnIsunordered},
{"ldexp", FnLdexp},
{"ldexp", FnLdexp},
{"log", FnLog},
{"log10", FnLog10},
{"log1p", FnLog1p},
{"log2", FnLog2},
{"logb", FnLogb},
{"lrint", FnLrint},
{"lround", FnLround},
{"max", FnFmax},
{"min", FnFmin},
{"nearbyint", FnNearbyint},
{"oct", FnOct},
{"pow", FnPow},
{"powi", FnPowi},
{"print", FnPrint},
{"remainder", FnRemainder},
{"rint", FnRint},
{"rol", FnRol},
{"rolb", FnRolb},
{"roll", FnRoll},
{"rolq", FnRolq},
{"rolw", FnRolw},
{"ror", FnRor},
{"rorb", FnRorb},
{"rorl", FnRorl},
{"rorq", FnRorq},
{"rorw", FnRorw},
{"round", FnRound},
{"rounddown", FnRounddown},
{"rounddown2pow", FnRounddown2pow},
{"roundup", FnRoundup},
{"roundup2log", FnRoundup2log},
{"roundup2pow", FnRoundup2pow},
{"sar", FnSar},
{"sarb", FnSarb},
{"sarl", FnSarl},
{"sarq", FnSarq},
{"sarw", FnSarw},
{"scalb", FnScalb},
{"signbit", FnSignbit},
{"signbit", FnSignbit},
{"significand", FnSignificand},
{"sin", FnSin},
{"sqrt", FnSqrt},
{"tan", FnTan},
{"time", FnTime},
{"trunc", FnTrunc},
{"ungray", FnUngray},
};
static long double CallFunction(struct Token fn, struct Numbers *args) {
int l, r, m, p;
l = 0;
r = ARRAYLEN(kFunctions) - 1;
while (l <= r) {
m = (l + r) >> 1;
p = strncmp(kFunctions[m].s, fn.s, fn.n);
if (p < 0) {
l = m + 1;
} else if (p > 0) {
r = m - 1;
} else {
return kFunctions[m].f(args);
}
}
MissingFunctionError();
}
static void Tokenize(const char *s, size_t size) {
size_t n;
char *se;
for (se = s + size; s < se; s += n, ++g_column) {
n = 1;
switch (*s & 0xff) {
case ' ':
case '\t':
case '\v':
case '\r':
break;
case '\n':
++g_line;
g_column = 0;
break;
case 'A' ... 'Z':
case 'a' ... 'z':
n = strspn(s, "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz");
Parse(g_parser, SYMBOL, (struct Token){s, n});
break;
case '0':
n = strspn(s, "xXbB0123456789abcdefABCDEF");
Parse(g_parser, NUMBER, (struct Token){s, n});
n += strspn(s + n, "LUlu");
break;
case '1' ... '9':
n = strspn(s, "0123456789.");
if (s[n] == 'e' || s[n] == 'E') {
++n;
if (s[n] == '+' || s[n] == '-') ++n;
n += strspn(s + n, "0123456789");
}
Parse(g_parser, NUMBER, (struct Token){s, n});
n += strspn(s + n, "LUlu");
break;
case '(':
Parse(g_parser, LP, (struct Token){0, 0});
break;
case ')':
Parse(g_parser, RP, (struct Token){0, 0});
break;
case ',':
Parse(g_parser, COMMA, (struct Token){0, 0});
break;
case '^':
Parse(g_parser, XOR, (struct Token){0, 0});
break;
case '%':
Parse(g_parser, REM, (struct Token){0, 0});
break;
case '+':
Parse(g_parser, PLUS, (struct Token){0, 0});
break;
case '-':
Parse(g_parser, MINUS, (struct Token){0, 0});
break;
case '~':
Parse(g_parser, NOT, (struct Token){0, 0});
break;
case '/':
if (s[1] == '/') {
Parse(g_parser, DDIV, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, DIV, (struct Token){0, 0});
}
break;
case '*':
if (s[1] == '*') {
Parse(g_parser, EXP, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, MUL, (struct Token){0, 0});
}
break;
case '|':
if (s[1] == '|') {
Parse(g_parser, LOR, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, OR, (struct Token){0, 0});
}
break;
case '&':
if (s[1] == '&') {
Parse(g_parser, LAND, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, AND, (struct Token){0, 0});
}
break;
case '!':
if (s[1] == '=') {
Parse(g_parser, NE, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, LNOT, (struct Token){0, 0});
}
break;
case '=':
if (s[1] == '=') {
Parse(g_parser, EQ, (struct Token){0, 0});
++n;
} else {
LexError();
}
break;
case '>':
if (s[1] == '=') {
Parse(g_parser, GE, (struct Token){0, 0});
++n;
} else if (s[1] == '>') {
Parse(g_parser, SHR, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, GT, (struct Token){0, 0});
}
break;
case '<':
if (s[1] == '=') {
Parse(g_parser, LE, (struct Token){0, 0});
++n;
} else if (s[1] == '<') {
Parse(g_parser, SHL, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, LT, (struct Token){0, 0});
}
break;
default:
LexError();
}
}
}
int main(int argc, char *argv[]) {
int i;
int ec;
int fd;
size_t n;
char *buf;
ssize_t rc;
size_t bufcap;
if (!(ec = setjmp(jb))) {
if (argc > 1) {
ParseInit(g_parser);
bufcap = BIGPAGESIZE;
buf = malloc(bufcap);
for (i = 1; i < argc; ++i) {
g_file = argv[i];
g_line = 0;
g_column = 0;
n = 0; /* wut */
if ((fd = open(g_file, O_RDONLY)) == -1) SyscallError("open");
for (;;) {
if ((rc = read(fd, buf, bufcap)) == -1) SyscallError("read");
if (!(n = rc)) break;
Tokenize(buf, n);
}
close(fd);
Parse(g_parser, 0, (struct Token){0, 0});
}
ParseFinalize(g_parser);
} else {
g_file = "/dev/stdin";
g_line = 0;
g_column = 0;
buf = NULL;
bufcap = 0;
while (getline(&buf, &bufcap, stdin) != -1) {
if ((n = strlen(buf))) {
ParseInit(g_parser);
if (!setjmp(jb)) {
Tokenize("print(", 6);
Tokenize(buf, n);
Tokenize(")", 1);
Parse(g_parser, 0, (struct Token){0, 0});
}
ParseFinalize(g_parser);
}
}
}
}
free(buf);
return ec;
}

24
tool/calc/calc.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef COSMOPOLITAN_TOOL_CALC_CALC_H_
#define COSMOPOLITAN_TOOL_CALC_CALC_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Token {
const char *s;
size_t n;
};
struct Numbers {
struct Numbers *n;
long double x;
};
static void SyntaxError(void) noreturn;
static long double ParseNumber(struct Token);
static void NumbersFree(struct Numbers *);
static struct Numbers *NumbersAppend(struct Numbers *, long double);
static long double CallFunction(struct Token, struct Numbers *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_CALC_CALC_H_ */

93
tool/calc/calc.lst Normal file
View file

@ -0,0 +1,93 @@
abs
acos
asin
atan
atan2
bin
bitreverse16
bitreverse32
bitreverse64
bitreverse8
bsfl
bsfl
bsr
bsr
cbrt
ceil
copysign
cos
exp
exp10
exp2
expm1
fabs
ffs
ffsl
floor
fmax
fmin
fmod
fpclassify
gray
hex
hypot
ilogb
isfinite
isgreater
isgreaterequal
isinf
isless
islessequal
islessgreater
isnan
isnormal
isunordered
ldexp
ldexp
log
log10
log1p
log2
logb
lrint
lround
max
min
nearbyint
oct
pow
powi
print
remainder
rint
rol
rolb
roll
rolq
rolw
ror
rorb
rorl
rorq
rorw
round
rounddown
rounddown2pow
roundup
roundup2log
roundup2pow
sar
sarb
sarl
sarq
sarw
scalb
signbit
signbit
significand
sin
sqrt
tan
time
trunc
ungray

75
tool/calc/calc.mk Normal file
View file

@ -0,0 +1,75 @@
#-*-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_CALC
TOOL_CALC = $(TOOL_LIB_A_DEPS) $(TOOL_LIB_A)
TOOL_CALC_A = o/$(MODE)/tool/calc/calc.a
TOOL_CALC_FILES := $(wildcard tool/calc/*)
TOOL_CALC_COMS = $(TOOL_CALC_OBJS:%.o=%.com)
TOOL_CALC_SRCS = $(filter %.c,$(TOOL_CALC_FILES))
TOOL_CALC_HDRS = $(filter %.h,$(TOOL_CALC_FILES))
TOOL_CALC_OBJS = \
$(TOOL_CALC_SRCS:%=o/$(MODE)/%.zip.o) \
$(TOOL_CALC_SRCS:%.c=o/$(MODE)/%.o)
TOOL_CALC_COMS = \
$(TOOL_CALC_SRCS:%.c=o/$(MODE)/%.com)
TOOL_CALC_BINS = \
$(TOOL_CALC_COMS) \
$(TOOL_CALC_COMS:%=%.dbg)
TOOL_CALC_CHECKS = \
$(TOOL_CALC_HDRS:%=o/$(MODE)/%.ok)
TOOL_CALC_DIRECTDEPS = \
LIBC_BITS \
LIBC_CALLS \
LIBC_CONV \
LIBC_LOG \
LIBC_FMT \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STUBS \
LIBC_STR \
LIBC_SYSV \
LIBC_TINYMATH \
LIBC_X \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_DTOA
TOOL_CALC_DEPS := \
$(call uniq,$(foreach x,$(TOOL_CALC_DIRECTDEPS),$($(x))))
$(TOOL_CALC_A): \
tool/calc/ \
$(TOOL_CALC_A).pkg \
$(TOOL_CALC_OBJS)
$(TOOL_CALC_A).pkg: \
$(TOOL_CALC_OBJS) \
$(foreach x,$(TOOL_CALC_DIRECTDEPS),$($(x)_A).pkg)
o/tool/calc/calc.h.inc: o/tool/calc/calc.c.inc
o/tool/calc/calc.c.inc: \
tool/calc/calc.y \
$(THIRD_PARTY_LEMON)
@$(LEMON) -l -d$(@D) $<
o/$(MODE)/tool/calc/%.com.dbg: \
$(TOOL_CALC_DEPS) \
$(TOOL_CALC_A) \
o/$(MODE)/tool/calc/%.o \
$(TOOL_CALC_A).pkg \
$(CRT) \
$(APE)
@$(APELINK)
.PHONY: o/$(MODE)/tool/calc
o/$(MODE)/tool/calc: \
$(TOOL_CALC_BINS) \
$(TOOL_CALC_CHECKS)

81
tool/calc/calc.y Normal file
View file

@ -0,0 +1,81 @@
/*-*- 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 {
#include "libc/stdio/stdio.h"
#include "tool/calc/calc.h"
#include "libc/calls/calls.h"
#include "libc/str/str.h"
#include "third_party/dtoa/dtoa.h"
#include "libc/x/x.h"
#include "libc/runtime/gc.h"
#include "libc/math.h"
}
%token_type {struct Token}
%type number {long double}
%syntax_error { SyntaxError(); }
%left LOR.
%left LAND.
%left OR.
%left XOR.
%left AND.
%left EQ NE.
%left LT LE GT GE.
%left SHL SHR.
%left PLUS MINUS.
%left MUL DIV DDIV REM.
%right NOT LNOT.
%right EXP.
program ::= number.
number(A) ::= NUMBER(B). { A = ParseNumber(B); }
number(A) ::= LP number(B) RP. { A = B; }
number(A) ::= LNOT number(B). { A = !B; }
number(A) ::= NOT number(B). { A = ~(long)B; }
number(A) ::= PLUS number(B). { A = +B; } [NOT]
number(A) ::= MINUS number(B). { A = -B; } [NOT]
number(A) ::= SYMBOL(F) LP numbers(N) RP. { A = CallFunction(F, N); }
number(A) ::= number(B) EQ number(C). { A = B == C; }
number(A) ::= number(B) NE number(C). { A = B != C; }
number(A) ::= number(B) LT number(C). { A = B < C; }
number(A) ::= number(B) LE number(C). { A = B <= C; }
number(A) ::= number(B) GT number(C). { A = B > C; }
number(A) ::= number(B) GE number(C). { A = B >= C; }
number(A) ::= number(B) LOR number(C). { A = B || C; }
number(A) ::= number(B) LAND number(C). { A = B && C; }
number(A) ::= number(B) PLUS number(C). { A = B + C; }
number(A) ::= number(B) MINUS number(C). { A = B - C; }
number(A) ::= number(B) MUL number(C). { A = B * C; }
number(A) ::= number(B) DIV number(C). { A = B / C; }
number(A) ::= number(B) REM number(C). { A = remainderl(B, C); }
number(A) ::= number(B) EXP number(C). { A = powl(B, C); }
number(A) ::= number(B) DDIV number(C). { A = truncl(B / C); }
number(A) ::= number(B) OR number(C). { A = (long)B | (long)C; }
number(A) ::= number(B) XOR number(C). { A = (long)B ^ (long)C; }
number(A) ::= number(B) AND number(C). { A = (long)B & (long)C; }
number(A) ::= number(B) SHL number(C). { A = (long)B << (long)C; }
number(A) ::= number(B) SHR number(C). { A = (long)B >> (long)C; }
%type numbers {struct Numbers *}
%destructor numbers { NumbersFree($$); }
numbers(A) ::= . { A = 0; }
numbers(A) ::= number(B). { A = NumbersAppend(0, B); }
numbers(A) ::= numbers(A) COMMA number(B). { A = NumbersAppend(A, B); }

View file

@ -30,6 +30,7 @@ TOOL_DECODE_DIRECTDEPS = \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RAND \
LIBC_TIME \
LIBC_RUNTIME \
LIBC_RUNTIME \
LIBC_STDIO \

View file

@ -128,7 +128,6 @@
"__msabi"
"microarchitecture"
"targetclones"
"winstruct"
"testonly"
"forcealignargpointer"
"textexit"
@ -136,8 +135,6 @@
"noinline"
"noclone"
"donothing"
"byanymeansnecessary"
"threadlocal"
"printfesque"
"flattenout"
"mallocesque"

33
tool/tags/keywords.c Normal file
View 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 "tool/tags/keywords.inc"
#include "tool/tags/tags.h"
/**
* Returns small number for HTTP header, or -1 if not found.
*/
int GetKeyword(const char *str, size_t len) {
const struct KeywordSlot *slot;
if ((slot = LookupKeyword(str, len))) {
return slot->code;
} else {
return -1;
}
}

161
tool/tags/keywords.gperf Normal file
View file

@ -0,0 +1,161 @@
%{
#include "libc/str/str.h"
#include "tool/tags/tags.h"
#include "o/tool/tags/tags.h.inc"
%}
%compare-strncmp
%language=ANSI-C
%readonly-tables
%struct-type
%define lookup-function-name LookupKeyword
struct KeywordSlot { char *name; int code; };
%%
auto, TK_AUTO
break, TK_BREAK
case, TK_CASE
char, TK_CHAR
const, TK_CONST
continue, TK_CONTINUE
default, TK_DEFAULT
do, TK_DO
double, TK_DOUBLE
else, TK_ELSE
enum, TK_ENUM
extern, TK_EXTERN
float, TK_FLOAT
for, TK_FOR
goto, TK_GOTO
if, TK_IF
inline, TK_INLINE
int, TK_INT
long, TK_LONG
register, TK_REGISTER
restrict, TK_RESTRICT
return, TK_RETURN
short, TK_SHORT
signed, TK_SIGNED
sizeof, TK_SIZEOF
static, TK_STATIC
struct, TK_STRUCT
switch, TK_SWITCH
typedef, TK_TYPEDEF
union, TK_UNION
unsigned, TK_UNSIGNED
void, TK_VOID
volatile, TK_VOLATILE
while, TK_WHILE
_Alignas, TK_ALIGNAS
_Alignof, TK_ALIGNOF
_Atomic, TK_ATOMIC
_Bool, TK_BOOL
_Complex, TK_COMPLEX
_Generic, TK_GENERIC
_Imaginary, TK_IMAGINARY
_Noreturn, TK_NORETURN
_Static_assert, TK_STATIC_ASSERT
_Thread_local, TK_THREAD_LOCAL
elif, TK_ELIF
endif, TK_ENDIF
ifdef, TK_IFDEF
ifndef, TK_IFNDEF
define, TK_DEFINE
undef, TK_UNDEF
include, TK_INCLUDE
line, TK_LINE
error, TK_ERROR
pragma, TK_PRAGMA
asm, TK_ASM
__attribute__, TK_ATTRIBUTE
__restrict__, TK_RESTRICT
__typeof__, TK_TYPEOF
__typeof, TK_TYPEOF
__inline, TK_INLINE
__const__, TK_CONST
__label__, TK_LABEL
__noinline__, TK_LABEL
__force_align_arg_pointer__, TK_FORCE_ALIGN_ARG_POINTER
__always_inline__, TK_ALWAYS_INLINE
__gnu_inline__, TK_GNU_INLINE
__alignof__, TK_ALIGNOF
__asm__, TK_ASM
__auto_type, TK_AUTO_TYPE
__byte__, TK_BYTE
__complex__, TK_COMPLEX
__imag__, TK_IMAG
__may_alias__, TK_MAY_ALIAS
__noreturn__, TK_NORETURN
__packed__, TK_PACKED
__pointer__, TK_POINTER
__printf__, TK_PRINTF
__real__, TK_REAL
__scanf__, TK_SCANF
__strfmon__, TK_STRFMON
__strftime__, TK_STRFTIME
__strong__, TK_STRONG
__target__, TK_TARGET
__transparent_union__, TK_TRANSPARENT_UNION
__volatile__, TK_VOLATILE
__word__, TK_WORD
__alias__, TK_ALIAS
__aligned__, TK_ALIGNED
__alloc_align__, TK_ALLOC_ALIGN
__alloc_size__, TK_ALLOC_SIZE
__artificial__, TK_ARTIFICIAL
__assume_aligned__, TK_ASSUME_ALIGNED
__cold__, TK_COLD
__constructor__, TK_CONSTRUCTOR
__destructor__, TK_DESTRUCTOR
__copy__, TK_COPY
__deprecated__, TK_DEPRECATED
__error__, TK_ERROR
__warning__, TK_WARNING
__externally_visible__, TK_EXTERNALLY_VISIBLE
__flatten__, TK_FLATTEN
__format__, TK_FORMAT
__gnu_format__, TK_GNU_FORMAT
__gnu_printf__, TK_GNU_PRINTF
__gnu_scanf__, TK_GNU_SCANF
__format_arg__, TK_FORMAT_ARG
__hot__, TK_HOT
__ifunc__, TK_IFUNC
__interrupt__, TK_INTERRUPT
__interrupt_handler__, TK_INTERRUPT_HANDLER
__no_caller_saved_registers__, TK_NO_CALLER_SAVED_REGISTERS
__leaf__, TK_LEAF
__malloc__, TK_MALLOC
__no_icf__, TK_NO_ICF
__no_instrument_function__, TK_NO_INSTRUMENT_FUNCTION
__no_profile_instrument_function__, TK_NO_PROFILE_INSTRUMENT_FUNCTION
__no_reorder__, TK_NO_REORDER
__no_sanitize__, TK_NO_SANITIZE
__no_sanitize_address__, TK_NO_SANITIZE_ADDRESS
__no_address_safety_analysis__, TK_NO_ADDRESS_SAFETY_ANALYSIS
__no_sanitize_thread__, TK_NO_SANITIZE_THREAD
__no_sanitize_undefined__, TK_NO_SANITIZE_UNDEFINED
__no_split_stack__, TK_NO_SPLIT_STACK
__no_stack_limit__, TK_NO_STACK_LIMIT
__noclone__, TK_NOCLONE
__noipa__, TK_NOIPA
__nonnull__, TK_NONNULL
__noplt__, TK_NOPLT
__nothrow__, TK_NOTHROW
__optimize__, TK_OPTIMIZE
__pure__, TK_PURE
__patchable_function_entry__, TK_PATCHABLE_FUNCTION_ENTRY
__returns_nonnull__, TK_RETURNS_NONNULL
__returns_twice__, TK_RETURNS_TWICE
__section__, TK_SECTION
__sentinel__, TK_SENTINEL
__simd__, TK_SIMD
__target_clones__, TK_TARGET_CLONES
__unused__, TK_UNUSED
__used__, TK_USED
__visibility__, TK_VISIBILITY
__warn_unused_result__, TK_WARN_UNUSED_RESULT
__params_nonnull__, TK_PARAMS_NONNULL
__weak__, TK_WEAK
__vector_size__, TK_VECTOR_SIZE
__ms_abi__, TK_MS_ABI
__mode__, TK_MODE
__optnone__, TK_OPTNONE
__nodebug__, TK_NODEBUG

516
tool/tags/keywords.inc Normal file
View file

@ -0,0 +1,516 @@
/* ANSI-C code produced by gperf version 3.1 */
/* Command-line: gperf keywords.gperf */
/* Computed positions: -k'1-3,5,8' */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
/* The character set is not based on ISO-646. */
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
#endif
#line 1 "keywords.gperf"
#include "libc/str/str.h"
#include "tool/tags/tags.h"
#include "o/tool/tags/tags.h.inc"
#line 11 "keywords.gperf"
struct KeywordSlot { char *name; int code; };
#define TOTAL_KEYWORDS 149
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 34
#define MIN_HASH_VALUE 15
#define MAX_HASH_VALUE 485
/* maximum key range = 471, duplicates = 0 */
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static unsigned int
hash (register const char *str, register size_t len)
{
static const unsigned short asso_values[] =
{
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 0, 5, 5, 486, 486,
486, 5, 486, 0, 486, 486, 486, 486, 0, 486,
486, 486, 486, 5, 0, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 45, 0, 40, 120, 160,
80, 60, 0, 130, 0, 55, 15, 486, 175, 20,
10, 0, 5, 70, 125, 10, 40, 0, 40, 145,
20, 20, 0, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
486, 486, 486, 486, 486, 486, 486
};
register unsigned int hval = len;
switch (hval)
{
default:
hval += asso_values[(unsigned char)str[7]+1];
/*FALLTHROUGH*/
case 7:
case 6:
case 5:
hval += asso_values[(unsigned char)str[4]+1];
/*FALLTHROUGH*/
case 4:
case 3:
hval += asso_values[(unsigned char)str[2]];
/*FALLTHROUGH*/
case 2:
hval += asso_values[(unsigned char)str[1]];
/*FALLTHROUGH*/
case 1:
hval += asso_values[(unsigned char)str[0]];
break;
}
return hval;
}
const struct KeywordSlot *
LookupKeyword (register const char *str, register size_t len)
{
static const struct KeywordSlot wordlist[] =
{
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""},
#line 35 "keywords.gperf"
{"short", TK_SHORT},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""},
#line 28 "keywords.gperf"
{"if", TK_IF},
#line 56 "keywords.gperf"
{"_Thread_local", TK_THREAD_LOCAL},
{""}, {""}, {""}, {""}, {""},
#line 54 "keywords.gperf"
{"_Noreturn", TK_NORETURN},
{""}, {""}, {""}, {""}, {""},
#line 42 "keywords.gperf"
{"union", TK_UNION},
#line 60 "keywords.gperf"
{"ifndef", TK_IFNDEF},
{""},
#line 67 "keywords.gperf"
{"asm", TK_ASM},
#line 23 "keywords.gperf"
{"enum", TK_ENUM},
#line 50 "keywords.gperf"
{"_Bool", TK_BOOL},
#line 37 "keywords.gperf"
{"sizeof", TK_SIZEOF},
{""}, {""}, {""}, {""}, {""},
#line 20 "keywords.gperf"
{"do", TK_DO},
{""},
#line 13 "keywords.gperf"
{"auto", TK_AUTO},
{""}, {""}, {""},
#line 43 "keywords.gperf"
{"unsigned", TK_UNSIGNED},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 119 "keywords.gperf"
{"__hot__", TK_HOT},
#line 152 "keywords.gperf"
{"__used__", TK_USED},
#line 44 "keywords.gperf"
{"void", TK_VOID},
{""},
#line 160 "keywords.gperf"
{"__optnone__", TK_OPTNONE},
#line 49 "keywords.gperf"
{"_Atomic", TK_ATOMIC},
{""},
#line 55 "keywords.gperf"
{"_Static_assert", TK_STATIC_ASSERT},
{""},
#line 21 "keywords.gperf"
{"double", TK_DOUBLE},
{""},
#line 30 "keywords.gperf"
{"int", TK_INT},
{""},
#line 114 "keywords.gperf"
{"__format__", TK_FORMAT},
#line 38 "keywords.gperf"
{"static", TK_STATIC},
#line 148 "keywords.gperf"
{"__sentinel__", TK_SENTINEL},
#line 143 "keywords.gperf"
{"__pure__", TK_PURE},
#line 118 "keywords.gperf"
{"__format_arg__", TK_FORMAT_ARG},
#line 130 "keywords.gperf"
{"__no_sanitize__", TK_NO_SANITIZE},
#line 141 "keywords.gperf"
{"__nothrow__", TK_NOTHROW},
#line 142 "keywords.gperf"
{"__optimize__", TK_OPTIMIZE},
#line 149 "keywords.gperf"
{"__simd__", TK_SIMD},
#line 129 "keywords.gperf"
{"__no_reorder__", TK_NO_REORDER},
#line 94 "keywords.gperf"
{"__strong__", TK_STRONG},
#line 88 "keywords.gperf"
{"__pointer__", TK_POINTER},
#line 133 "keywords.gperf"
{"__no_sanitize_thread__", TK_NO_SANITIZE_THREAD},
#line 131 "keywords.gperf"
{"__no_sanitize_address__", TK_NO_SANITIZE_ADDRESS},
#line 138 "keywords.gperf"
{"__noipa__", TK_NOIPA},
#line 134 "keywords.gperf"
{"__no_sanitize_undefined__", TK_NO_SANITIZE_UNDEFINED},
#line 92 "keywords.gperf"
{"__strfmon__", TK_STRFMON},
#line 76 "keywords.gperf"
{"__force_align_arg_pointer__", TK_FORCE_ALIGN_ARG_POINTER},
#line 26 "keywords.gperf"
{"for", TK_FOR},
{""}, {""},
#line 139 "keywords.gperf"
{"__nonnull__", TK_NONNULL},
#line 41 "keywords.gperf"
{"typedef", TK_TYPEDEF},
{""}, {""},
#line 158 "keywords.gperf"
{"__ms_abi__", TK_MS_ABI},
#line 24 "keywords.gperf"
{"extern", TK_EXTERN},
#line 93 "keywords.gperf"
{"__strftime__", TK_STRFTIME},
#line 135 "keywords.gperf"
{"__no_split_stack__", TK_NO_SPLIT_STACK},
#line 128 "keywords.gperf"
{"__no_profile_instrument_function__", TK_NO_PROFILE_INSTRUMENT_FUNCTION},
{""},
#line 81 "keywords.gperf"
{"__auto_type", TK_AUTO_TYPE},
#line 75 "keywords.gperf"
{"__noinline__", TK_LABEL},
#line 85 "keywords.gperf"
{"__may_alias__", TK_MAY_ALIAS},
{""}, {""},
#line 61 "keywords.gperf"
{"define", TK_DEFINE},
#line 80 "keywords.gperf"
{"__asm__", TK_ASM},
#line 51 "keywords.gperf"
{"_Complex", TK_COMPLEX},
#line 123 "keywords.gperf"
{"__no_caller_saved_registers__", TK_NO_CALLER_SAVED_REGISTERS},
#line 95 "keywords.gperf"
{"__target__", TK_TARGET},
{""}, {""}, {""},
#line 99 "keywords.gperf"
{"__alias__", TK_ALIAS},
{""},
#line 100 "keywords.gperf"
{"__aligned__", TK_ALIGNED},
#line 150 "keywords.gperf"
{"__target_clones__", TK_TARGET_CLONES},
{""},
#line 103 "keywords.gperf"
{"__artificial__", TK_ARTIFICIAL},
{""},
#line 79 "keywords.gperf"
{"__alignof__", TK_ALIGNOF},
#line 86 "keywords.gperf"
{"__noreturn__", TK_NORETURN},
#line 155 "keywords.gperf"
{"__params_nonnull__", TK_PARAMS_NONNULL},
#line 102 "keywords.gperf"
{"__alloc_size__", TK_ALLOC_SIZE},
#line 101 "keywords.gperf"
{"__alloc_align__", TK_ALLOC_ALIGN},
#line 127 "keywords.gperf"
{"__no_instrument_function__", TK_NO_INSTRUMENT_FUNCTION},
{""},
#line 121 "keywords.gperf"
{"__interrupt__", TK_INTERRUPT},
#line 110 "keywords.gperf"
{"__error__", TK_ERROR},
{""}, {""},
#line 112 "keywords.gperf"
{"__externally_visible__", TK_EXTERNALLY_VISIBLE},
#line 72 "keywords.gperf"
{"__inline", TK_INLINE},
#line 27 "keywords.gperf"
{"goto", TK_GOTO},
#line 17 "keywords.gperf"
{"const", TK_CONST},
#line 122 "keywords.gperf"
{"__interrupt_handler__", TK_INTERRUPT_HANDLER},
#line 97 "keywords.gperf"
{"__volatile__", TK_VOLATILE},
#line 159 "keywords.gperf"
{"__mode__", TK_MODE},
#line 140 "keywords.gperf"
{"__noplt__", TK_NOPLT},
#line 25 "keywords.gperf"
{"float", TK_FLOAT},
{""}, {""}, {""}, {""}, {""},
#line 66 "keywords.gperf"
{"pragma", TK_PRAGMA},
#line 19 "keywords.gperf"
{"default", TK_DEFAULT},
#line 104 "keywords.gperf"
{"__assume_aligned__", TK_ASSUME_ALIGNED},
#line 31 "keywords.gperf"
{"long", TK_LONG},
#line 132 "keywords.gperf"
{"__no_address_safety_analysis__", TK_NO_ADDRESS_SAFETY_ANALYSIS},
#line 137 "keywords.gperf"
{"__noclone__", TK_NOCLONE},
{""},
#line 18 "keywords.gperf"
{"continue", TK_CONTINUE},
#line 120 "keywords.gperf"
{"__ifunc__", TK_IFUNC},
#line 53 "keywords.gperf"
{"_Imaginary", TK_IMAGINARY},
#line 147 "keywords.gperf"
{"__section__", TK_SECTION},
{""},
#line 52 "keywords.gperf"
{"_Generic", TK_GENERIC},
#line 153 "keywords.gperf"
{"__visibility__", TK_VISIBILITY},
#line 151 "keywords.gperf"
{"__unused__", TK_UNUSED},
#line 36 "keywords.gperf"
{"signed", TK_SIGNED},
{""}, {""},
#line 16 "keywords.gperf"
{"char", TK_CHAR},
#line 46 "keywords.gperf"
{"while", TK_WHILE},
{""},
#line 77 "keywords.gperf"
{"__always_inline__", TK_ALWAYS_INLINE},
{""}, {""}, {""},
#line 161 "keywords.gperf"
{"__nodebug__", TK_NODEBUG},
{""},
#line 33 "keywords.gperf"
{"restrict", TK_RESTRICT},
#line 15 "keywords.gperf"
{"case", TK_CASE},
{""}, {""}, {""},
#line 82 "keywords.gperf"
{"__byte__", TK_BYTE},
{""},
#line 125 "keywords.gperf"
{"__malloc__", TK_MALLOC},
#line 113 "keywords.gperf"
{"__flatten__", TK_FLATTEN},
{""},
#line 45 "keywords.gperf"
{"volatile", TK_VOLATILE},
{""},
#line 62 "keywords.gperf"
{"undef", TK_UNDEF},
{""}, {""}, {""},
#line 91 "keywords.gperf"
{"__scanf__", TK_SCANF},
{""}, {""},
#line 146 "keywords.gperf"
{"__returns_twice__", TK_RETURNS_TWICE},
{""},
#line 145 "keywords.gperf"
{"__returns_nonnull__", TK_RETURNS_NONNULL},
#line 157 "keywords.gperf"
{"__vector_size__", TK_VECTOR_SIZE},
{""}, {""},
#line 136 "keywords.gperf"
{"__no_stack_limit__", TK_NO_STACK_LIMIT},
{""},
#line 126 "keywords.gperf"
{"__no_icf__", TK_NO_ICF},
#line 34 "keywords.gperf"
{"return", TK_RETURN},
{""},
#line 144 "keywords.gperf"
{"__patchable_function_entry__", TK_PATCHABLE_FUNCTION_ENTRY},
#line 64 "keywords.gperf"
{"line", TK_LINE},
#line 87 "keywords.gperf"
{"__packed__", TK_PACKED},
#line 29 "keywords.gperf"
{"inline", TK_INLINE},
{""}, {""},
#line 22 "keywords.gperf"
{"else", TK_ELSE},
#line 89 "keywords.gperf"
{"__printf__", TK_PRINTF},
{""}, {""},
#line 98 "keywords.gperf"
{"__word__", TK_WORD},
{""}, {""},
#line 111 "keywords.gperf"
{"__warning__", TK_WARNING},
{""}, {""},
#line 73 "keywords.gperf"
{"__const__", TK_CONST},
{""},
#line 39 "keywords.gperf"
{"struct", TK_STRUCT},
{""}, {""},
#line 107 "keywords.gperf"
{"__destructor__", TK_DESTRUCTOR},
{""}, {""}, {""},
#line 47 "keywords.gperf"
{"_Alignas", TK_ALIGNAS},
{""},
#line 59 "keywords.gperf"
{"ifdef", TK_IFDEF},
#line 83 "keywords.gperf"
{"__complex__", TK_COMPLEX},
#line 63 "keywords.gperf"
{"include", TK_INCLUDE},
#line 84 "keywords.gperf"
{"__imag__", TK_IMAG},
#line 78 "keywords.gperf"
{"__gnu_inline__", TK_GNU_INLINE},
#line 106 "keywords.gperf"
{"__constructor__", TK_CONSTRUCTOR},
{""}, {""},
#line 105 "keywords.gperf"
{"__cold__", TK_COLD},
#line 115 "keywords.gperf"
{"__gnu_format__", TK_GNU_FORMAT},
{""}, {""},
#line 69 "keywords.gperf"
{"__restrict__", TK_RESTRICT},
{""},
#line 116 "keywords.gperf"
{"__gnu_printf__", TK_GNU_PRINTF},
#line 58 "keywords.gperf"
{"endif", TK_ENDIF},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 57 "keywords.gperf"
{"elif", TK_ELIF},
{""},
#line 40 "keywords.gperf"
{"switch", TK_SWITCH},
{""}, {""}, {""}, {""}, {""}, {""},
#line 68 "keywords.gperf"
{"__attribute__", TK_ATTRIBUTE},
{""}, {""}, {""},
#line 154 "keywords.gperf"
{"__warn_unused_result__", TK_WARN_UNUSED_RESULT},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 65 "keywords.gperf"
{"error", TK_ERROR},
{""}, {""},
#line 108 "keywords.gperf"
{"__copy__", TK_COPY},
{""}, {""}, {""}, {""}, {""},
#line 109 "keywords.gperf"
{"__deprecated__", TK_DEPRECATED},
{""}, {""}, {""},
#line 71 "keywords.gperf"
{"__typeof", TK_TYPEOF},
{""},
#line 70 "keywords.gperf"
{"__typeof__", TK_TYPEOF},
#line 96 "keywords.gperf"
{"__transparent_union__", TK_TRANSPARENT_UNION},
{""},
#line 90 "keywords.gperf"
{"__real__", TK_REAL},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 117 "keywords.gperf"
{"__gnu_scanf__", TK_GNU_SCANF},
{""}, {""}, {""}, {""},
#line 48 "keywords.gperf"
{"_Alignof", TK_ALIGNOF},
{""}, {""}, {""}, {""},
#line 156 "keywords.gperf"
{"__weak__", TK_WEAK},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 32 "keywords.gperf"
{"register", TK_REGISTER},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""},
#line 124 "keywords.gperf"
{"__leaf__", TK_LEAF},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""},
#line 74 "keywords.gperf"
{"__label__", TK_LABEL},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""},
#line 14 "keywords.gperf"
{"break", TK_BREAK}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register unsigned int key = hash (str, len);
if (key <= MAX_HASH_VALUE)
{
register const char *s = wordlist[key].name;
if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
return &wordlist[key];
}
}
return 0;
}

343
tool/tags/tags.c Normal file
View file

@ -0,0 +1,343 @@
/*-*- 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/conv/conv.h"
#include "libc/errno.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "o/tool/tags/tags.c.inc"
#include "o/tool/tags/tags.h.inc"
#include "tool/tags/tags.h"
static jmp_buf jb;
static int g_line;
static int g_column;
static const char *g_file;
static yyParser g_parser[1];
noreturn static void Error(const char *msg) {
fprintf(stderr, "%s:%d:%d: %s\n", g_file, g_line, g_column, msg);
longjmp(jb, 1);
}
noreturn static void SyntaxError(void) {
Error("SYNTAX ERROR");
}
noreturn static void LexError(void) {
Error("LEX ERROR");
}
noreturn static void MissingArgumentError(void) {
Error("MISSING ARGUMENT");
}
noreturn static void MissingFunctionError(void) {
Error("MISSING FUNCTION");
}
noreturn static void SyscallError(const char *name) {
fprintf(stderr, "ERROR: %s[%s]: %d\n", name, g_file, errno);
exit(1);
}
static void ExprsFree(struct Exprs *n) {
if (n) {
ExprsFree(n->n);
free(n);
}
}
static struct Exprs *ExprsAppend(struct Exprs *n, long double x) {
struct Exprs *a;
a = malloc(sizeof(struct Exprs));
a->n = n;
a->x = x;
return a;
}
static long double ParseExpr(struct Token t) {
char *ep;
ep = t.s + t.n;
if (t.s[0] == '0') {
return strtoumax(t.s, &ep, 0);
} else {
return strtod(t.s, &ep);
}
}
static long double CallFunction(struct Token fn, struct Exprs *args) {
return 0;
}
static void Tokenize(const char *s, size_t size) {
int kw;
size_t n;
char *se;
for (se = s + size; s < se; s += n, ++g_column) {
n = 1;
switch (*s & 0xff) {
case ' ':
case '\t':
case '\v':
case '\r':
case 0x0C:
break;
case '\n':
++g_line;
g_column = 0;
break;
case 'A' ... 'Z':
case 'a' ... 'z':
n = strspn(s, "$"
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz");
if ((kw = GetKeyword(s, n)) != -1) {
Parse(g_parser, kw, (struct Token){s, n});
} else {
Parse(g_parser, TK_SYMBOL, (struct Token){s, n});
}
break;
case '0':
n = strspn(s, "xXbB0123456789abcdefABCDEF");
Parse(g_parser, TK_I_CONSTANT, (struct Token){s, n});
n += strspn(s + n, "LUlu");
break;
case '1' ... '9':
n = strspn(s, "0123456789.");
if (s[n] == 'e' || s[n] == 'E') {
++n;
if (s[n] == '+' || s[n] == '-') ++n;
n += strspn(s + n, "0123456789");
}
Parse(g_parser, memchr(s, '.', n) ? TK_F_CONSTANT : TK_I_CONSTANT,
(struct Token){s, n});
n += strspn(s + n, "LUlu");
break;
case ';':
Parse(g_parser, TK_SEMI, (struct Token){0, 0});
break;
case '(':
Parse(g_parser, TK_LP, (struct Token){0, 0});
break;
case ')':
Parse(g_parser, TK_RP, (struct Token){0, 0});
break;
case '[':
Parse(g_parser, TK_LSB, (struct Token){0, 0});
break;
case ']':
Parse(g_parser, TK_RSB, (struct Token){0, 0});
break;
case '{':
Parse(g_parser, TK_LCB, (struct Token){0, 0});
break;
case '}':
Parse(g_parser, TK_RCB, (struct Token){0, 0});
break;
case '?':
Parse(g_parser, TK_QUESTION, (struct Token){0, 0});
break;
case ':':
Parse(g_parser, TK_COLON, (struct Token){0, 0});
break;
case ',':
Parse(g_parser, TK_COMMA, (struct Token){0, 0});
break;
case '^':
if (s[1] == '=') {
Parse(g_parser, TK_XOR_ASSIGN, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_XOR, (struct Token){0, 0});
}
break;
case '%':
if (s[1] == '=') {
Parse(g_parser, TK_REM_ASSIGN, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_REM, (struct Token){0, 0});
}
break;
case '.':
Parse(g_parser, TK_DOT, (struct Token){0, 0});
break;
case '+':
if (s[1] == '=') {
Parse(g_parser, TK_ADD_ASSIGN, (struct Token){0, 0});
++n;
} else if (s[1] == '+') {
Parse(g_parser, TK_INC, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_ADD, (struct Token){0, 0});
}
break;
case '-':
if (s[1] == '=') {
Parse(g_parser, TK_SUB_ASSIGN, (struct Token){0, 0});
++n;
} else if (s[1] == '-') {
Parse(g_parser, TK_DEC, (struct Token){0, 0});
++n;
} else if (s[1] == '>') {
Parse(g_parser, TK_ARROW, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_SUB, (struct Token){0, 0});
}
break;
case '~':
Parse(g_parser, TK_TILDE, (struct Token){0, 0});
break;
case '/':
if (s[1] == '=') {
Parse(g_parser, TK_DIV_ASSIGN, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_DIV, (struct Token){0, 0});
}
break;
case '*':
if (s[1] == '=') {
Parse(g_parser, TK_MUL_ASSIGN, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_STAR, (struct Token){0, 0});
}
break;
case '|':
if (s[1] == '|') {
Parse(g_parser, TK_OR_LOGICAL, (struct Token){0, 0});
++n;
} else if (s[1] == '=') {
Parse(g_parser, TK_OR_ASSIGN, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_OR, (struct Token){0, 0});
}
break;
case '&':
if (s[1] == '&') {
Parse(g_parser, TK_AND_LOGICAL, (struct Token){0, 0});
++n;
} else if (s[1] == '=') {
Parse(g_parser, TK_AND_ASSIGN, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_AND, (struct Token){0, 0});
}
break;
case '!':
if (s[1] == '=') {
Parse(g_parser, TK_NOTEQUAL, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_EXCLAIM, (struct Token){0, 0});
}
break;
case '=':
if (s[1] == '=') {
Parse(g_parser, TK_EQUAL, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_EQ, (struct Token){0, 0});
}
break;
case '>':
if (s[1] == '=') {
Parse(g_parser, TK_GE, (struct Token){0, 0});
++n;
} else if (s[1] == '>') {
if (s[2] == '=') {
Parse(g_parser, TK_SHR_ASSIGN, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_SHR, (struct Token){0, 0});
}
++n;
} else {
Parse(g_parser, TK_GT, (struct Token){0, 0});
}
break;
case '<':
if (s[1] == '=') {
Parse(g_parser, TK_LE, (struct Token){0, 0});
++n;
} else if (s[1] == '<') {
if (s[2] == '=') {
Parse(g_parser, TK_SHL_ASSIGN, (struct Token){0, 0});
++n;
} else {
Parse(g_parser, TK_SHL, (struct Token){0, 0});
}
++n;
} else {
Parse(g_parser, TK_LT, (struct Token){0, 0});
}
break;
default:
LexError();
}
}
}
int main(int argc, char *argv[]) {
int i;
int ec;
int fd;
size_t n;
char *buf;
ssize_t rc;
size_t bufcap;
bufcap = BIGPAGESIZE;
buf = malloc(bufcap);
if (!(ec = setjmp(jb))) {
for (i = 1; i < argc; ++i) {
g_file = argv[i];
g_line = 0;
g_column = 0;
n = 0; /* wut */
if ((fd = open(g_file, O_RDONLY)) == -1) SyscallError("open");
ParseInit(g_parser);
for (;;) {
if ((rc = read(fd, buf, bufcap)) == -1) SyscallError("read");
if (!(n = rc)) break;
Tokenize(buf, n);
}
close(fd);
Parse(g_parser, 0, (struct Token){0, 0});
ParseFinalize(g_parser);
}
}
free(buf);
return ec;
}

25
tool/tags/tags.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef COSMOPOLITAN_TOOL_TAGS_TAGS_H_
#define COSMOPOLITAN_TOOL_TAGS_TAGS_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Token {
const char *s;
size_t n;
};
struct Exprs {
struct Exprs *n;
long double x;
};
static void SyntaxError(void) noreturn;
static long double ParseExpr(struct Token);
static void ExprsFree(struct Exprs *);
static struct Exprs *ExprsAppend(struct Exprs *, long double);
static long double CallFunction(struct Token, struct Exprs *);
int GetKeyword(const char *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_TAGS_TAGS_H_ */

75
tool/tags/tags.mk Normal file
View file

@ -0,0 +1,75 @@
#-*-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_TAGS
TOOL_TAGS = $(TOOL_LIB_A_DEPS) $(TOOL_LIB_A)
TOOL_TAGS_A = o/$(MODE)/tool/tags/tags.a
TOOL_TAGS_FILES := $(wildcard tool/tags/*)
TOOL_TAGS_COMS = $(TOOL_TAGS_OBJS:%.o=%.com)
TOOL_TAGS_SRCS = $(filter %.c,$(TOOL_TAGS_FILES))
TOOL_TAGS_HDRS = $(filter %.h,$(TOOL_TAGS_FILES))
TOOL_TAGS_OBJS = \
$(TOOL_TAGS_SRCS:%=o/$(MODE)/%.zip.o) \
$(TOOL_TAGS_SRCS:%.c=o/$(MODE)/%.o)
TOOL_TAGS_COMS = \
$(TOOL_TAGS_SRCS:%.c=o/$(MODE)/%.com)
TOOL_TAGS_BINS = \
$(TOOL_TAGS_COMS) \
$(TOOL_TAGS_COMS:%=%.dbg)
TOOL_TAGS_CHECKS = \
$(TOOL_TAGS_HDRS:%=o/$(MODE)/%.ok)
TOOL_TAGS_DIRECTDEPS = \
LIBC_BITS \
LIBC_CALLS \
LIBC_CONV \
LIBC_LOG \
LIBC_FMT \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STUBS \
LIBC_STR \
LIBC_SYSV \
LIBC_TINYMATH \
LIBC_X \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_DTOA
TOOL_TAGS_DEPS := \
$(call uniq,$(foreach x,$(TOOL_TAGS_DIRECTDEPS),$($(x))))
$(TOOL_TAGS_A): \
tool/tags/ \
$(TOOL_TAGS_A).pkg \
$(TOOL_TAGS_OBJS)
$(TOOL_TAGS_A).pkg: \
$(TOOL_TAGS_OBJS) \
$(foreach x,$(TOOL_TAGS_DIRECTDEPS),$($(x)_A).pkg)
o/tool/tags/tags.h.inc: o/tool/tags/tags.c.inc
o/tool/tags/tags.c.inc: \
tool/tags/tags.y \
$(THIRD_PARTY_LEMON)
@$(LEMON) -l -d$(@D) $<
o/$(MODE)/tool/tags/%.com.dbg: \
$(TOOL_TAGS_DEPS) \
$(TOOL_TAGS_A) \
o/$(MODE)/tool/tags/%.o \
$(TOOL_TAGS_A).pkg \
$(CRT) \
$(APE)
@$(APELINK)
.PHONY: o/$(MODE)/tool/tags
o/$(MODE)/tool/tags: \
$(TOOL_TAGS_BINS) \
$(TOOL_TAGS_CHECKS)

436
tool/tags/tags.y Normal file
View file

@ -0,0 +1,436 @@
/*-*- 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 {
#include "libc/stdio/stdio.h"
#include "tool/tags/tags.h"
#include "libc/calls/calls.h"
#include "libc/str/str.h"
#include "third_party/dtoa/dtoa.h"
#include "libc/x/x.h"
#include "libc/runtime/gc.h"
#include "libc/math.h"
}
/**
* C parser.
*
* “The grammar of C seems remarkably well-behaved. It is almost
* LALR(1). More precisely, the automaton built for C by an LALR(1)
* parser generator exhibits only two conflicts: (1) a shift/reduce
* conflict caused by dangling else ambiguity and (2) a shift/reduce
* conflict caused by the _Atomic( ambiguity. In both cases, the
* desired behavior can be obtained by instructing the parser to
* prefer shifting.” Quoth Jacques-Henri Jourdan & François Pottier
*
*/
%token_prefix TK_
%token_type {struct Token}
%type expr {long double}
%syntax_error { SyntaxError(); }
%token AUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM EXTERN.
%token FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT RETURN SHORT SIGNED.
%token SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE WHILE.
%token ALIGNAS ALIGNOF ATOMIC BOOL COMPLEX GENERIC IMAGINARY NORETURN INCLUDE.
%token STATIC_ASSERT THREAD_LOCAL ELIF ENDIF IFDEF IFNDEF DEFINE UNDEF PRAGMA.
%token LINE ERROR SYMBOL ATTRIBUTE RESTRICT TYPEOF TYPEOF INLINE CONST LABEL.
%token FORCE_ALIGN_ARG_POINTER ALWAYS_INLINE GNU_INLINE ALIGNOF ASM AUTO_TYPE.
%token BYTE COMPLEX IMAG MAY_ALIAS NORETURN PACKED POINTER PRINTF REAL SCANF.
%token STRFMON STRFTIME STRONG TARGET TRANSPARENT_UNION VOLATILE WORD ALIAS.
%token ALIGNED ALLOC_ALIGN ALLOC_SIZE ARTIFICIAL ASSUME_ALIGNED COLD.
%token CONSTRUCTOR DESTRUCTOR COPY DEPRECATED ERROR WARNING EXTERNALLY_VISIBLE.
%token FLATTEN FORMAT GNU_FORMAT GNU_PRINTF GNU_SCANF FORMAT_ARG HOT IFUNC.
%token INTERRUPT INTERRUPT_HANDLER NO_CALLER_SAVED_REGISTERS LEAF MALLOC NO_ICF.
%token NO_INSTRUMENT_FUNCTION NO_PROFILE_INSTRUMENT_FUNCTION NO_REORDER.
%token NO_SANITIZE NO_SANITIZE_ADDRESS NO_ADDRESS_SAFETY_ANALYSIS.
%token NO_SANITIZE_THREAD NO_SANITIZE_UNDEFINED NO_SPLIT_STACK NO_STACK_LIMIT.
%token NOCLONE NOIPA NONNULL NOPLT NOTHROW OPTIMIZE PURE.
%token PATCHABLE_FUNCTION_ENTRY RETURNS_NONNULL RETURNS_TWICE SECTION SENTINEL.
%token SIMD TARGET_CLONES UNUSED USED VISIBILITY WARN_UNUSED_RESULT.
%token PARAMS_NONNULL WEAK VECTOR_SIZE MS_ABI MODE OPTNONE NODEBUG.
%left IF.
%left ELSE.
%right COMMA.
%right EQ ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN REM_ASSIGN.
%right SHL_ASSIGN SHR_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN.
%right QUESTION COLON.
%left OR_LOGICAL.
%left AND_LOGICAL.
%left OR.
%left XOR.
%left AND.
%left EQUAL NOTEQUAL.
%left LT LE GT GE.
%left SHL SHR.
%left ADD SUB.
%left STAR DIV REM.
%right TILDE EXCLAIM INC DEC AMP SIZEOF ALIGNOF.
%left DOT ARROW LP RP RSB LSB.
program ::= translation_unit.
translation_unit ::= external_declaration.
translation_unit ::= translation_unit external_declaration.
external_declaration ::= function_definition.
external_declaration ::= declaration.
function_definition ::= declaration_specifiers declarator declaration_list compound_statement.
function_definition ::= declaration_specifiers declarator compound_statement.
declaration_list ::= declaration.
declaration_list ::= declaration_list declaration.
jump_statement ::= GOTO IDENTIFIER SEMI.
jump_statement ::= CONTINUE SEMI.
jump_statement ::= BREAK SEMI.
jump_statement ::= RETURN SEMI.
jump_statement ::= RETURN expression SEMI.
iteration_statement ::= WHILE LP expression RP statement.
iteration_statement ::= DO statement WHILE LP expression RP SEMI.
iteration_statement ::= FOR LP expression_statement expression_statement RP statement.
iteration_statement ::= FOR LP expression_statement expression_statement expression RP statement.
iteration_statement ::= FOR LP declaration expression_statement RP statement.
iteration_statement ::= FOR LP declaration expression_statement expression RP statement.
selection_statement ::= IF LP expression RP statement ELSE statement.
selection_statement ::= IF LP expression RP statement.
selection_statement ::= SWITCH LP expression RP statement.
expression_statement ::= SEMI.
expression_statement ::= expression SEMI.
block_item ::= declaration.
block_item ::= statement.
block_item_list ::= block_item.
block_item_list ::= block_item_list block_item.
compound_statement ::= LCB RCB.
compound_statement ::= LCB block_item_list RCB.
labeled_statement ::= IDENTIFIER COLON statement.
labeled_statement ::= CASE constant_expression COLON statement.
labeled_statement ::= DEFAULT COLON statement.
statement ::= labeled_statement.
statement ::= compound_statement.
statement ::= expression_statement.
statement ::= selection_statement.
statement ::= iteration_statement.
statement ::= jump_statement.
static_assert_declaration ::= STATIC_ASSERT LP constant_expression COMMA STRING_LITERAL RP SEMI.
designator ::= LSB constant_expression RSB.
designator ::= DOT IDENTIFIER.
designator_list ::= designator.
designator_list ::= designator_list designator.
designation ::= designator_list EQ.
initializer_list ::= designation initializer.
initializer_list ::= initializer.
initializer_list ::= initializer_list COMMA designation initializer.
initializer_list ::= initializer_list COMMA initializer.
initializer ::= LCB initializer_list RCB.
initializer ::= LCB initializer_list COMMA RCB.
initializer ::= assignment_expression.
direct_abstract_declarator ::= LP abstract_declarator RP.
direct_abstract_declarator ::= LSB RSB.
direct_abstract_declarator ::= LSB STAR RSB.
direct_abstract_declarator ::= LSB STATIC type_qualifier_list assignment_expression RSB.
direct_abstract_declarator ::= LSB STATIC assignment_expression RSB.
direct_abstract_declarator ::= LSB type_qualifier_list STATIC assignment_expression RSB.
direct_abstract_declarator ::= LSB type_qualifier_list assignment_expression RSB.
direct_abstract_declarator ::= LSB type_qualifier_list RSB.
direct_abstract_declarator ::= LSB assignment_expression RSB.
direct_abstract_declarator ::= direct_abstract_declarator LSB RSB.
direct_abstract_declarator ::= direct_abstract_declarator LSB STAR RSB.
direct_abstract_declarator ::= direct_abstract_declarator LSB STATIC type_qualifier_list assignment_expression RSB.
direct_abstract_declarator ::= direct_abstract_declarator LSB STATIC assignment_expression RSB.
direct_abstract_declarator ::= direct_abstract_declarator LSB type_qualifier_list assignment_expression RSB.
direct_abstract_declarator ::= direct_abstract_declarator LSB type_qualifier_list STATIC assignment_expression RSB.
direct_abstract_declarator ::= direct_abstract_declarator LSB type_qualifier_list RSB.
direct_abstract_declarator ::= direct_abstract_declarator LSB assignment_expression RSB.
direct_abstract_declarator ::= LP RP.
direct_abstract_declarator ::= LP parameter_type_list RP.
direct_abstract_declarator ::= direct_abstract_declarator LP RP.
direct_abstract_declarator ::= direct_abstract_declarator LP parameter_type_list RP.
abstract_declarator ::= pointer direct_abstract_declarator.
abstract_declarator ::= pointer.
abstract_declarator ::= direct_abstract_declarator.
type_name ::= specifier_qualifier_list abstract_declarator.
type_name ::= specifier_qualifier_list.
primary_expression ::= IDENTIFIER.
primary_expression ::= constant.
primary_expression ::= string.
primary_expression ::= LP expression RP.
primary_expression ::= generic_selection.
constant ::= I_CONSTANT.
constant ::= F_CONSTANT.
constant ::= ENUMERATION_CONSTANT.
enumeration_constant ::= IDENTIFIER.
string ::= STRING_LITERAL.
string ::= FUNC_NAME.
generic_selection ::= GENERIC LP assignment_expression COMMA generic_assoc_list RP.
generic_assoc_list ::= generic_association.
generic_assoc_list ::= generic_assoc_list COMMA generic_association.
generic_association ::= type_name COLON assignment_expression.
generic_association ::= DEFAULT COLON assignment_expression.
postfix_expression ::= primary_expression.
postfix_expression ::= postfix_expression LSB expression RSB.
postfix_expression ::= postfix_expression LP RP.
postfix_expression ::= postfix_expression LP argument_expression_list RP.
postfix_expression ::= postfix_expression DOT IDENTIFIER.
postfix_expression ::= postfix_expression ARROW IDENTIFIER.
postfix_expression ::= postfix_expression INC.
postfix_expression ::= postfix_expression DEC.
postfix_expression ::= LP type_name RP LCB initializer_list RCB.
postfix_expression ::= LP type_name RP LCB initializer_list COMMA RCB.
argument_expression_list ::= assignment_expression.
argument_expression_list ::= argument_expression_list COMMA assignment_expression.
unary_expression ::= postfix_expression.
unary_expression ::= INC unary_expression.
unary_expression ::= DEC unary_expression.
unary_expression ::= unary_operator cast_expression.
unary_expression ::= SIZEOF unary_expression.
unary_expression ::= SIZEOF LP type_name RP.
unary_expression ::= ALIGNOF LP type_name RP.
unary_operator ::= AMP.
unary_operator ::= STAR.
unary_operator ::= ADD.
unary_operator ::= SUB.
unary_operator ::= TILDE.
unary_operator ::= EXCLAIM.
cast_expression ::= unary_expression.
cast_expression ::= LP type_name RP cast_expression.
multiplicative_expression ::= cast_expression.
multiplicative_expression ::= multiplicative_expression STAR cast_expression.
multiplicative_expression ::= multiplicative_expression DIV cast_expression.
multiplicative_expression ::= multiplicative_expression REM cast_expression.
additive_expression ::= multiplicative_expression.
additive_expression ::= additive_expression ADD multiplicative_expression.
additive_expression ::= additive_expression SUB multiplicative_expression.
shift_expression ::= additive_expression.
shift_expression ::= shift_expression SHL additive_expression.
shift_expression ::= shift_expression SHR additive_expression.
relational_expression ::= shift_expression.
relational_expression ::= relational_expression LT shift_expression.
relational_expression ::= relational_expression GT shift_expression.
relational_expression ::= relational_expression LE shift_expression.
relational_expression ::= relational_expression GE shift_expression.
equality_expression ::= relational_expression.
equality_expression ::= equality_expression EQUAL relational_expression.
equality_expression ::= equality_expression NOTEQUAL relational_expression.
and_expression ::= equality_expression.
and_expression ::= and_expression AMP equality_expression.
exclusive_or_expression ::= and_expression.
exclusive_or_expression ::= exclusive_or_expression XOR and_expression.
inclusive_or_expression ::= exclusive_or_expression.
inclusive_or_expression ::= inclusive_or_expression OR exclusive_or_expression.
logical_and_expression ::= inclusive_or_expression.
logical_and_expression ::= logical_and_expression AND_LOGICAL inclusive_or_expression.
logical_or_expression ::= logical_and_expression.
logical_or_expression ::= logical_or_expression OR_LOGICAL logical_and_expression.
conditional_expression ::= logical_or_expression.
conditional_expression ::= logical_or_expression QUESTION expression COLON conditional_expression.
assignment_expression ::= conditional_expression.
assignment_expression ::= unary_expression assignment_operator assignment_expression.
assignment_operator ::= EQ.
assignment_operator ::= MUL_ASSIGN.
assignment_operator ::= DIV_ASSIGN.
assignment_operator ::= REM_ASSIGN.
assignment_operator ::= ADD_ASSIGN.
assignment_operator ::= SUB_ASSIGN.
assignment_operator ::= SHL_ASSIGN.
assignment_operator ::= SHR_ASSIGN.
assignment_operator ::= AND_ASSIGN.
assignment_operator ::= XOR_ASSIGN.
assignment_operator ::= OR_ASSIGN.
expression ::= assignment_expression.
expression ::= expression COMMA assignment_expression.
constant_expression ::= conditional_expression. /* with constraints */
declaration ::= declaration_specifiers SEMI.
declaration ::= declaration_specifiers init_declarator_list SEMI.
declaration ::= static_assert_declaration.
declaration_specifiers ::= storage_class_specifier declaration_specifiers.
declaration_specifiers ::= storage_class_specifier.
declaration_specifiers ::= type_specifier declaration_specifiers.
declaration_specifiers ::= type_specifier.
declaration_specifiers ::= type_qualifier declaration_specifiers.
declaration_specifiers ::= type_qualifier.
declaration_specifiers ::= function_specifier declaration_specifiers.
declaration_specifiers ::= function_specifier.
declaration_specifiers ::= alignment_specifier declaration_specifiers.
declaration_specifiers ::= alignment_specifier.
init_declarator_list ::= init_declarator.
init_declarator_list ::= init_declarator_list COMMA init_declarator.
init_declarator ::= declarator EQ initializer.
init_declarator ::= declarator.
storage_class_specifier ::= TYPEDEF. /* identifiers must be flagged as TYPEDEF_NAME */
storage_class_specifier ::= EXTERN.
storage_class_specifier ::= STATIC.
storage_class_specifier ::= THREAD_LOCAL.
storage_class_specifier ::= AUTO.
storage_class_specifier ::= REGISTER.
type_specifier ::= VOID.
type_specifier ::= CHAR.
type_specifier ::= SHORT.
type_specifier ::= INT.
type_specifier ::= LONG.
type_specifier ::= FLOAT.
type_specifier ::= DOUBLE.
type_specifier ::= SIGNED.
type_specifier ::= UNSIGNED.
type_specifier ::= BOOL.
type_specifier ::= COMPLEX.
type_specifier ::= IMAGINARY. /* non-mandated extension */
type_specifier ::= struct_or_union_specifier.
type_specifier ::= enum_specifier.
type_specifier ::= TYPEDEF_NAME. /* after it has been defined as such */
struct_or_union_specifier ::= struct_or_union LCB struct_declaration_list RCB.
struct_or_union_specifier ::= struct_or_union IDENTIFIER LCB struct_declaration_list RCB.
struct_or_union_specifier ::= struct_or_union IDENTIFIER.
struct_or_union ::= STRUCT.
struct_or_union ::= UNION.
struct_declaration_list ::= struct_declaration.
struct_declaration_list ::= struct_declaration_list struct_declaration.
struct_declaration ::= specifier_qualifier_list SEMI. /* for anonymous struct/union */
struct_declaration ::= specifier_qualifier_list struct_declarator_list SEMI.
struct_declaration ::= static_assert_declaration.
specifier_qualifier_list ::= type_specifier specifier_qualifier_list.
specifier_qualifier_list ::= type_specifier.
specifier_qualifier_list ::= type_qualifier specifier_qualifier_list.
specifier_qualifier_list ::= type_qualifier.
struct_declarator_list ::= struct_declarator.
struct_declarator_list ::= struct_declarator_list COMMA struct_declarator.
struct_declarator ::= COLON constant_expression.
struct_declarator ::= declarator COLON constant_expression.
struct_declarator ::= declarator.
enum_specifier ::= ENUM LCB enumerator_list RCB.
enum_specifier ::= ENUM LCB enumerator_list COMMA RCB.
enum_specifier ::= ENUM IDENTIFIER LCB enumerator_list RCB.
enum_specifier ::= ENUM IDENTIFIER LCB enumerator_list COMMA RCB.
enum_specifier ::= ENUM IDENTIFIER.
enumerator_list ::= enumerator.
enumerator_list ::= enumerator_list COMMA enumerator.
enumerator ::= enumeration_constant EQ constant_expression.
enumerator ::= enumeration_constant.
type_qualifier ::= CONST.
type_qualifier ::= RESTRICT.
type_qualifier ::= VOLATILE.
type_qualifier ::= ATOMIC.
function_specifier ::= INLINE.
function_specifier ::= NORETURN.
alignment_specifier ::= ALIGNAS LP type_name RP.
alignment_specifier ::= ALIGNAS LP constant_expression RP.
declarator ::= pointer direct_declarator.
declarator ::= direct_declarator.
direct_declarator ::= IDENTIFIER.
direct_declarator ::= LP declarator RP.
direct_declarator ::= direct_declarator LSB RSB.
direct_declarator ::= direct_declarator LSB STAR RSB.
direct_declarator ::= direct_declarator LSB STATIC type_qualifier_list assignment_expression RSB.
direct_declarator ::= direct_declarator LSB STATIC assignment_expression RSB.
direct_declarator ::= direct_declarator LSB type_qualifier_list STAR RSB.
direct_declarator ::= direct_declarator LSB type_qualifier_list STATIC assignment_expression RSB.
direct_declarator ::= direct_declarator LSB type_qualifier_list assignment_expression RSB.
direct_declarator ::= direct_declarator LSB type_qualifier_list RSB.
direct_declarator ::= direct_declarator LSB assignment_expression RSB.
direct_declarator ::= direct_declarator LP parameter_type_list RP.
direct_declarator ::= direct_declarator LP RP.
direct_declarator ::= direct_declarator LP identifier_list RP.
pointer ::= STAR type_qualifier_list pointer.
pointer ::= STAR type_qualifier_list.
pointer ::= STAR pointer.
pointer ::= STAR.
type_qualifier_list ::= type_qualifier.
type_qualifier_list ::= type_qualifier_list type_qualifier.
parameter_type_list ::= parameter_list COMMA ELLIPSIS.
parameter_type_list ::= parameter_list.
parameter_list ::= parameter_declaration.
parameter_list ::= parameter_list COMMA parameter_declaration.
parameter_declaration ::= declaration_specifiers declarator.
parameter_declaration ::= declaration_specifiers abstract_declarator.
parameter_declaration ::= declaration_specifiers.
identifier_list ::= IDENTIFIER.
identifier_list ::= identifier_list COMMA IDENTIFIER.

View file

@ -4,8 +4,10 @@
.PHONY: o/$(MODE)/tool
o/$(MODE)/tool: \
o/$(MODE)/tool/build \
o/$(MODE)/tool/calc \
o/$(MODE)/tool/decode \
o/$(MODE)/tool/hash \
o/$(MODE)/tool/net \
o/$(MODE)/tool/tags \
o/$(MODE)/tool/viz \
o/$(MODE)/tool/cc