mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-26 22:38:30 +00:00
Add minor improvements and cleanup
This commit is contained in:
parent
9e3e985ae5
commit
feed0d2b0e
163 changed files with 2286 additions and 2245 deletions
|
@ -34,7 +34,10 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/bing.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/pcmpeqb.h"
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/color.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
|
@ -143,21 +146,19 @@ FEATURES\n\
|
|||
#define kXmmHex 1
|
||||
#define kXmmChar 2
|
||||
|
||||
#define CTRL(C) ((C) ^ 0100)
|
||||
#define kMouseLeftDown 0
|
||||
#define kMouseMiddleDown 1
|
||||
#define kMouseRightDown 2
|
||||
#define kMouseLeftUp 4
|
||||
#define kMouseMiddleUp 5
|
||||
#define kMouseRightUp 6
|
||||
#define kMouseLeftDrag 32
|
||||
#define kMouseMiddleDrag 33
|
||||
#define kMouseRightDrag 34
|
||||
#define kMouseWheelUp 64
|
||||
#define kMouseWheelDown 65
|
||||
|
||||
enum Mouse {
|
||||
kMouseLeftDown = 0,
|
||||
kMouseMiddleDown = 1,
|
||||
kMouseRightDown = 2,
|
||||
kMouseLeftUp = 4,
|
||||
kMouseMiddleUp = 5,
|
||||
kMouseRightUp = 6,
|
||||
kMouseLeftDrag = 32,
|
||||
kMouseMiddleDrag = 33,
|
||||
kMouseRightDrag = 34,
|
||||
kMouseWheelUp = 64,
|
||||
kMouseWheelDown = 65,
|
||||
};
|
||||
#define CTRL(C) ((C) ^ 0100)
|
||||
|
||||
struct MachineState {
|
||||
uint64_t ip;
|
||||
|
@ -171,6 +172,7 @@ struct MachineState {
|
|||
uint8_t xmm[16][16];
|
||||
struct MachineFpu fpu;
|
||||
struct MachineSse sse;
|
||||
struct MachineMemstat memstat;
|
||||
};
|
||||
|
||||
struct Panels {
|
||||
|
@ -196,8 +198,9 @@ struct Panels {
|
|||
struct Panel writedata;
|
||||
struct Panel stackhr;
|
||||
struct Panel stack;
|
||||
struct Panel status;
|
||||
};
|
||||
struct Panel p[20];
|
||||
struct Panel p[21];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -230,6 +233,7 @@ static int readzoom;
|
|||
static int writezoom;
|
||||
static int stackzoom;
|
||||
|
||||
static long ips;
|
||||
static long rombase;
|
||||
static long codesize;
|
||||
static int64_t opstart;
|
||||
|
@ -240,20 +244,23 @@ static int64_t writestart;
|
|||
static int64_t stackstart;
|
||||
static int64_t framesstart;
|
||||
static int64_t breakpointsstart;
|
||||
static uint64_t last_opcount;
|
||||
static char *codepath;
|
||||
static void *onbusted;
|
||||
static char *statusmessage;
|
||||
static struct Machine *m;
|
||||
static struct MachinePty *pty;
|
||||
static struct Pty *pty;
|
||||
|
||||
static struct Panels pan;
|
||||
static struct MachineState laststate;
|
||||
static struct Breakpoints breakpoints;
|
||||
static struct MachineMemstat lastmemstat;
|
||||
static struct Elf elf[1];
|
||||
static struct Dis dis[1];
|
||||
static uint8_t xmmtype[16];
|
||||
static uint8_t xmmsize[16];
|
||||
|
||||
long double last_seconds;
|
||||
static long double statusexpires;
|
||||
static struct termios oldterm;
|
||||
static char logpath[PATH_MAX];
|
||||
|
@ -386,6 +393,18 @@ static int64_t GetSp(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static int64_t ReadWord(uint8_t *p) {
|
||||
switch (GetPointerWidth()) {
|
||||
default:
|
||||
case 8:
|
||||
return Read64(p);
|
||||
case 4:
|
||||
return Read32(p);
|
||||
case 2:
|
||||
return Read16(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateXmmTypes(int regtype, int rmtype) {
|
||||
xmmtype[RexrReg(m->xedd->op.rde)] = regtype;
|
||||
if (IsModrmRegister(m->xedd->op.rde)) {
|
||||
|
@ -519,6 +538,18 @@ static void UpdateXmmType(void) {
|
|||
UpdateXmmSizes(1, 2);
|
||||
UpdateXmmTypes(kXmmIntegral, kXmmIntegral);
|
||||
break;
|
||||
case 0x128: // MOVAPS Vps Wps
|
||||
if (IsModrmRegister(m->xedd->op.rde)) {
|
||||
xmmtype[RexrReg(m->xedd->op.rde)] = xmmtype[RexbRm(m->xedd->op.rde)];
|
||||
xmmsize[RexrReg(m->xedd->op.rde)] = xmmsize[RexbRm(m->xedd->op.rde)];
|
||||
}
|
||||
break;
|
||||
case 0x129: // MOVAPS Wps Vps
|
||||
if (IsModrmRegister(m->xedd->op.rde)) {
|
||||
xmmtype[RexbRm(m->xedd->op.rde)] = xmmtype[RexrReg(m->xedd->op.rde)];
|
||||
xmmsize[RexbRm(m->xedd->op.rde)] = xmmsize[RexrReg(m->xedd->op.rde)];
|
||||
}
|
||||
break;
|
||||
case 0x16F: // MOVDQA Vdq Wdq
|
||||
if (Osz(m->xedd->op.rde) && IsModrmRegister(m->xedd->op.rde)) {
|
||||
xmmtype[RexrReg(m->xedd->op.rde)] = xmmtype[RexbRm(m->xedd->op.rde)];
|
||||
|
@ -671,7 +702,6 @@ static void OnSigAlarm(void) {
|
|||
|
||||
static void OnSigCont(void) {
|
||||
TuiRejuvinate();
|
||||
SetupDraw();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
|
@ -771,12 +801,12 @@ void TuiSetup(void) {
|
|||
LoadSyms();
|
||||
ResolveBreakpoints();
|
||||
ioctl(ttyout, TCGETS, &oldterm);
|
||||
xsigaction(SIGALRM, OnSigAlarm, 0, 0, 0);
|
||||
xsigaction(SIGINT, OnSigInt, 0, 0, oldsig + 3);
|
||||
atexit(TtyRestore2);
|
||||
once = true;
|
||||
report = true;
|
||||
}
|
||||
setitimer(ITIMER_REAL, &((struct itimerval){0}), NULL);
|
||||
xsigaction(SIGCONT, OnSigCont, SA_RESTART | SA_NODEFER, 0, oldsig + 2);
|
||||
CopyMachineState(&laststate);
|
||||
TuiRejuvinate();
|
||||
|
@ -798,6 +828,9 @@ static void ExecSetup(void) {
|
|||
}
|
||||
once = true;
|
||||
}
|
||||
setitimer(ITIMER_REAL,
|
||||
&((struct itimerval){{0, 1. / 60 * 1e6}, {0, 1. / 60 * 1e6}}),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void AppendPanel(struct Panel *p, long line, const char *s) {
|
||||
|
@ -807,12 +840,14 @@ static void AppendPanel(struct Panel *p, long line, const char *s) {
|
|||
}
|
||||
|
||||
static bool IsXmmNonZero(long start, long end) {
|
||||
long i, j;
|
||||
long i;
|
||||
uint8_t v1[16], vz[16];
|
||||
for (i = start; i < end; ++i) {
|
||||
for (j = 0; j < 16; ++j) {
|
||||
if (m->xmm[i][j]) {
|
||||
return true;
|
||||
}
|
||||
memset(vz, 0, 16);
|
||||
memcpy(v1, m->xmm[i], 16);
|
||||
pcmpeqb(v1, v1, vz);
|
||||
if (pmovmskb(v1) != 0xffff) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -840,16 +875,8 @@ static int PickNumberOfXmmRegistersToShow(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void SetupDraw(void) {
|
||||
int i, j, n, a, b, cpuy, ssey, dx[2], c2y[3], c3y[5];
|
||||
|
||||
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
||||
n = pan.p[i].bottom - pan.p[i].top;
|
||||
for (j = 0; j < n; ++j) {
|
||||
free(pan.p[i].lines[j].p);
|
||||
}
|
||||
free(pan.p[i].lines);
|
||||
}
|
||||
void SetupDraw(void) {
|
||||
int i, j, n, a, b, yn, cpuy, ssey, dx[2], c2y[3], c3y[5];
|
||||
|
||||
cpuy = 9;
|
||||
if (IsSegNonZero()) cpuy += 2;
|
||||
|
@ -861,20 +888,21 @@ static void SetupDraw(void) {
|
|||
dx[1] = txn >= a + b ? txn - a : txn;
|
||||
dx[0] = txn >= a + b + b ? txn - a - b : dx[1];
|
||||
|
||||
a = 1 / 8. * tyn;
|
||||
b = 3 / 8. * tyn;
|
||||
yn = tyn - 1;
|
||||
a = 1 / 8. * yn;
|
||||
b = 3 / 8. * yn;
|
||||
c2y[0] = a * .7;
|
||||
c2y[1] = a * 2;
|
||||
c2y[2] = a * 2 + b;
|
||||
if (tyn - c2y[2] > 26) {
|
||||
c2y[1] -= tyn - c2y[2] - 26;
|
||||
c2y[2] = tyn - 26;
|
||||
if (yn - c2y[2] > 26) {
|
||||
c2y[1] -= yn - c2y[2] - 26;
|
||||
c2y[2] = yn - 26;
|
||||
}
|
||||
if (tyn - c2y[2] < 26) {
|
||||
c2y[2] = tyn - 26;
|
||||
if (yn - c2y[2] < 26) {
|
||||
c2y[2] = yn - 26;
|
||||
}
|
||||
|
||||
a = (tyn - (cpuy + ssey) - 3) / 4;
|
||||
a = (yn - (cpuy + ssey) - 3) / 4;
|
||||
c3y[0] = cpuy;
|
||||
c3y[1] = cpuy + ssey;
|
||||
c3y[2] = cpuy + ssey + 1 + 1 + a * 1;
|
||||
|
@ -885,8 +913,8 @@ static void SetupDraw(void) {
|
|||
|
||||
pan.disassembly.top = 0;
|
||||
pan.disassembly.left = 0;
|
||||
pan.disassembly.bottom = tyn;
|
||||
pan.disassembly.right = dx[0];
|
||||
pan.disassembly.bottom = yn;
|
||||
pan.disassembly.right = dx[0] - 1;
|
||||
|
||||
/* COLUMN #2: BREAKPOINTS, MEMORY MAPS, BACKTRACE, DISPLAY */
|
||||
|
||||
|
@ -927,7 +955,7 @@ static void SetupDraw(void) {
|
|||
|
||||
pan.display.top = c2y[2] + 1;
|
||||
pan.display.left = dx[0];
|
||||
pan.display.bottom = tyn;
|
||||
pan.display.bottom = yn;
|
||||
pan.display.right = dx[1] - 1;
|
||||
|
||||
/* COLUMN #3: REGISTERS, VECTORS, CODE, MEMORY READS, MEMORY WRITES, STACK */
|
||||
|
@ -984,18 +1012,38 @@ static void SetupDraw(void) {
|
|||
|
||||
pan.stack.top = c3y[4] + 1;
|
||||
pan.stack.left = dx[1];
|
||||
pan.stack.bottom = tyn;
|
||||
pan.stack.bottom = yn;
|
||||
pan.stack.right = txn;
|
||||
|
||||
pan.status.top = yn;
|
||||
pan.status.left = 0;
|
||||
pan.status.bottom = yn + 1;
|
||||
pan.status.right = txn;
|
||||
|
||||
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
||||
if (pan.p[i].top > pan.p[i].bottom) pan.p[i].top = pan.p[i].bottom = 0;
|
||||
if (pan.p[i].left > pan.p[i].right) pan.p[i].left = pan.p[i].right = 0;
|
||||
pan.p[i].lines =
|
||||
xcalloc(pan.p[i].bottom - pan.p[i].top, sizeof(struct Buffer));
|
||||
if (pan.p[i].left > pan.p[i].right) {
|
||||
pan.p[i].left = pan.p[i].right = 0;
|
||||
}
|
||||
if (pan.p[i].top > pan.p[i].bottom) {
|
||||
pan.p[i].top = pan.p[i].bottom = 0;
|
||||
}
|
||||
n = pan.p[i].bottom - pan.p[i].top;
|
||||
if (n == pan.p[i].n) {
|
||||
for (j = 0; j < n; ++j) {
|
||||
pan.p[i].lines[j].i = 0;
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j < pan.p[i].n; ++j) {
|
||||
free(pan.p[i].lines[j].p);
|
||||
}
|
||||
free(pan.p[i].lines);
|
||||
pan.p[i].lines = xcalloc(n, sizeof(struct Buffer));
|
||||
pan.p[i].n = n;
|
||||
}
|
||||
}
|
||||
|
||||
MachinePtyResize(pty, pan.display.bottom - pan.display.top,
|
||||
pan.display.right - pan.display.left);
|
||||
PtyResize(pty, pan.display.bottom - pan.display.top,
|
||||
pan.display.right - pan.display.left);
|
||||
}
|
||||
|
||||
static long Disassemble(void) {
|
||||
|
@ -1043,30 +1091,30 @@ static void DrawHr(struct Panel *p, const char *s) {
|
|||
|
||||
void DrawTerminal(struct Panel *p) {
|
||||
long i, y, yn;
|
||||
if (pty->conf & kMachinePtyBell) {
|
||||
if (pty->conf & kPtyBell) {
|
||||
if (!alarmed) {
|
||||
alarmed = true;
|
||||
setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {0, 800000}}), NULL);
|
||||
}
|
||||
AppendStr(&pan.displayhr.lines[0], "\e[1m");
|
||||
}
|
||||
AppendStr(
|
||||
&pan.displayhr.lines[0],
|
||||
gc(xasprintf("──────────TELETYPEWRITER──%s──%s──%s──%s",
|
||||
(pty->conf & kMachinePtyLed1) ? "\e[1;31m◎\e[0m" : "○",
|
||||
(pty->conf & kMachinePtyLed2) ? "\e[1;32m◎\e[0m" : "○",
|
||||
(pty->conf & kMachinePtyLed3) ? "\e[1;33m◎\e[0m" : "○",
|
||||
(pty->conf & kMachinePtyLed4) ? "\e[1;34m◎\e[0m" : "○")));
|
||||
AppendStr(&pan.displayhr.lines[0],
|
||||
gc(xasprintf("──────────TELETYPEWRITER──%s──%s──%s──%s",
|
||||
(pty->conf & kPtyLed1) ? "\e[1;31m◎\e[0m" : "○",
|
||||
(pty->conf & kPtyLed2) ? "\e[1;32m◎\e[0m" : "○",
|
||||
(pty->conf & kPtyLed3) ? "\e[1;33m◎\e[0m" : "○",
|
||||
(pty->conf & kPtyLed4) ? "\e[1;34m◎\e[0m" : "○")));
|
||||
for (i = 36; i < pan.displayhr.right - pan.displayhr.left; ++i) {
|
||||
AppendWide(&pan.displayhr.lines[0], u'─');
|
||||
}
|
||||
for (yn = MIN(pty->yn, p->bottom - p->top), y = 0; y < yn; ++y) {
|
||||
MachinePtyAppendLine(pty, p->lines + y, y);
|
||||
PtyAppendLine(pty, p->lines + y, y);
|
||||
AppendStr(p->lines + y, "\e[0m");
|
||||
}
|
||||
}
|
||||
|
||||
void DrawDisplay(struct Panel *p) {
|
||||
if (p->top == p->bottom) return;
|
||||
switch (vidya) {
|
||||
case 7:
|
||||
DrawHr(&pan.displayhr, "MONOCHROME DISPLAY ADAPTER");
|
||||
|
@ -1140,6 +1188,7 @@ static void DrawSt(struct Panel *p, long i, long r) {
|
|||
|
||||
static void DrawCpu(struct Panel *p) {
|
||||
char buf[48];
|
||||
if (p->top == p->bottom) return;
|
||||
DrawRegister(p, 0, 7), DrawRegister(p, 0, 0), DrawSt(p, 0, 0);
|
||||
DrawRegister(p, 1, 6), DrawRegister(p, 1, 3), DrawSt(p, 1, 1);
|
||||
DrawRegister(p, 2, 2), DrawRegister(p, 2, 5), DrawSt(p, 2, 2);
|
||||
|
@ -1239,6 +1288,7 @@ static void DrawXmm(struct Panel *p, long i, long r) {
|
|||
|
||||
static void DrawSse(struct Panel *p) {
|
||||
long i;
|
||||
if (p->top == p->bottom) return;
|
||||
for (i = 0; i < MIN(16, MAX(0, p->bottom - p->top)); ++i) {
|
||||
DrawXmm(p, i, i);
|
||||
}
|
||||
|
@ -1314,6 +1364,7 @@ static void DrawMemory(struct Panel *p, int zoom, long startline, long histart,
|
|||
char buf[16];
|
||||
bool high, changed;
|
||||
long i, j, k, c, width;
|
||||
if (p->top == p->bottom) return;
|
||||
high = false;
|
||||
width = DUMPWIDTH * (1 << zoom);
|
||||
for (i = 0; i < p->bottom - p->top; ++i) {
|
||||
|
@ -1342,6 +1393,7 @@ static void DrawMemory(struct Panel *p, int zoom, long startline, long histart,
|
|||
static void DrawMaps(struct Panel *p) {
|
||||
int i;
|
||||
char *text, *p1, *p2;
|
||||
if (p->top == p->bottom) return;
|
||||
p1 = text = FormatPml4t(m);
|
||||
for (i = 0; p1; ++i, p1 = p2) {
|
||||
if ((p2 = strchr(p1, '\n'))) *p2++ = '\0';
|
||||
|
@ -1357,6 +1409,7 @@ static void DrawBreakpoints(struct Panel *p) {
|
|||
const char *name;
|
||||
char *s, buf[256];
|
||||
long i, line, sym;
|
||||
if (p->top == p->bottom) return;
|
||||
for (line = 0, i = breakpoints.i; i--;) {
|
||||
if (breakpoints.p[i].disable) continue;
|
||||
if (line >= breakpointsstart) {
|
||||
|
@ -1396,6 +1449,7 @@ static void DrawFrames(struct Panel *p) {
|
|||
const char *name;
|
||||
char *s, line[256];
|
||||
int64_t sp, bp, rp;
|
||||
if (p->top == p->bottom) return;
|
||||
rp = m->ip;
|
||||
bp = Read64(m->bp);
|
||||
sp = Read64(m->sp);
|
||||
|
@ -1427,8 +1481,8 @@ static void DrawFrames(struct Panel *p) {
|
|||
break;
|
||||
}
|
||||
sp = bp;
|
||||
bp = Read64(r + 0);
|
||||
rp = Read64(r + 8);
|
||||
bp = ReadWord(r + 0);
|
||||
rp = ReadWord(r + 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1466,8 +1520,60 @@ static bool IsExecuting(void) {
|
|||
return (action & (CONTINUE | STEP | NEXT | FINISH)) && !(action & FAILURE);
|
||||
}
|
||||
|
||||
static int AppendStat(struct Buffer *b, const char *name, int64_t value,
|
||||
bool changed) {
|
||||
int width;
|
||||
AppendChar(b, ' ');
|
||||
if (changed) AppendStr(b, "\e[31m");
|
||||
width = AppendFmt(b, "%,8ld %s", value, name);
|
||||
if (changed) AppendStr(b, "\e[39m");
|
||||
return 1 + width;
|
||||
}
|
||||
|
||||
void DrawStatus(struct Panel *p) {
|
||||
int yn, xn, rw;
|
||||
struct Buffer s;
|
||||
struct MachineMemstat *a, *b;
|
||||
yn = p->top - p->bottom;
|
||||
xn = p->right - p->left;
|
||||
if (!yn || !xn) return;
|
||||
rw = 0;
|
||||
a = &m->memstat;
|
||||
b = &lastmemstat;
|
||||
memset(&s, 0, sizeof(s));
|
||||
if (ips > 0) rw += AppendStat(&s, "ips", ips, false);
|
||||
rw += AppendStat(&s, "kb", m->real.n / 1024, false);
|
||||
rw += AppendStat(&s, "reserve", a->reserved, a->reserved != b->reserved);
|
||||
rw += AppendStat(&s, "commit", a->committed, a->committed != b->committed);
|
||||
rw += AppendStat(&s, "freed", a->freed, a->freed != b->freed);
|
||||
rw += AppendStat(&s, "tables", a->pagetables, a->pagetables != b->pagetables);
|
||||
rw += AppendStat(&s, "fds", m->fds.i, false);
|
||||
AppendFmt(&p->lines[0], "\e[7m%-*s%s\e[0m", xn - rw,
|
||||
statusmessage && nowl() < statusexpires ? statusmessage
|
||||
: "das blinkenlights",
|
||||
s.p);
|
||||
free(s.p);
|
||||
memcpy(b, a, sizeof(*a));
|
||||
}
|
||||
|
||||
static void PreventBufferbloat(void) {
|
||||
long double now, rate;
|
||||
static long double last;
|
||||
now = nowl();
|
||||
rate = 1. / 60;
|
||||
if (now - last < rate) {
|
||||
dsleep(rate - (now - last));
|
||||
}
|
||||
last = now;
|
||||
}
|
||||
|
||||
static void Redraw(void) {
|
||||
int i, j;
|
||||
ScrollOp(&pan.disassembly, GetDisIndex());
|
||||
if (last_opcount) {
|
||||
ips = unsignedsubtract(opcount, last_opcount) / (nowl() - last_seconds);
|
||||
}
|
||||
SetupDraw();
|
||||
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
||||
for (j = 0; j < pan.p[i].bottom - pan.p[i].top; ++j) {
|
||||
pan.p[i].lines[j].i = 0;
|
||||
|
@ -1478,7 +1584,7 @@ static void Redraw(void) {
|
|||
DrawCpu(&pan.registers);
|
||||
DrawSse(&pan.sse);
|
||||
DrawHr(&pan.breakpointshr, "BREAKPOINTS");
|
||||
DrawHr(&pan.mapshr, "MAPS");
|
||||
DrawHr(&pan.mapshr, "PML4T");
|
||||
DrawHr(&pan.frameshr, m->bofram[0] ? "PROTECTED FRAMES" : "FRAMES");
|
||||
DrawHr(&pan.ssehr, "SSE");
|
||||
DrawHr(&pan.codehr, "CODE");
|
||||
|
@ -1496,19 +1602,20 @@ static void Redraw(void) {
|
|||
m->writeaddr + m->writesize);
|
||||
DrawMemory(&pan.stack, stackzoom, stackstart, GetSp(),
|
||||
GetSp() + GetPointerWidth());
|
||||
DrawStatus(&pan.status);
|
||||
PreventBufferbloat();
|
||||
if (PrintPanels(ttyout, ARRAYLEN(pan.p), pan.p, tyn, txn) == -1) {
|
||||
LOGF("PrintPanels Interrupted");
|
||||
CHECK_EQ(EINTR, errno);
|
||||
}
|
||||
if (statusmessage && nowl() < statusexpires) {
|
||||
TtyWriteString(statusmessage);
|
||||
}
|
||||
last_opcount = opcount;
|
||||
last_seconds = nowl();
|
||||
CopyMachineState(&laststate);
|
||||
}
|
||||
|
||||
static void ReactiveDraw(void) {
|
||||
if (tuimode) {
|
||||
m->ip -= m->xedd->length;
|
||||
SetupDraw();
|
||||
Redraw();
|
||||
m->ip += m->xedd->length;
|
||||
tick = speed;
|
||||
|
@ -1518,7 +1625,7 @@ static void ReactiveDraw(void) {
|
|||
static void HandleAlarm(void) {
|
||||
alarmed = false;
|
||||
action &= ~ALARM;
|
||||
pty->conf &= ~kMachinePtyBell;
|
||||
pty->conf &= ~kPtyBell;
|
||||
free(statusmessage);
|
||||
statusmessage = NULL;
|
||||
}
|
||||
|
@ -1547,7 +1654,7 @@ static void HandleAppReadInterrupt(void) {
|
|||
}
|
||||
|
||||
static int OnPtyFdClose(int fd) {
|
||||
return 0;
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
static bool HasPendingInput(int fd) {
|
||||
|
@ -1564,7 +1671,7 @@ static ssize_t ReadPtyFdDirect(int fd, void *data, size_t size) {
|
|||
ssize_t rc;
|
||||
DEBUGF("ReadPtyFdDirect");
|
||||
buf = malloc(PAGESIZE);
|
||||
pty->conf |= kMachinePtyBlinkcursor;
|
||||
pty->conf |= kPtyBlinkcursor;
|
||||
if (tuimode) DisableMouseTracking();
|
||||
for (;;) {
|
||||
ReactiveDraw();
|
||||
|
@ -1573,11 +1680,11 @@ static ssize_t ReadPtyFdDirect(int fd, void *data, size_t size) {
|
|||
HandleAppReadInterrupt();
|
||||
}
|
||||
if (tuimode) EnableMouseTracking();
|
||||
pty->conf &= ~kMachinePtyBlinkcursor;
|
||||
pty->conf &= ~kPtyBlinkcursor;
|
||||
if (rc > 0) {
|
||||
MachinePtyWriteInput(pty, buf, rc);
|
||||
PtyWriteInput(pty, buf, rc);
|
||||
ReactiveDraw();
|
||||
rc = MachinePtyRead(pty, data, size);
|
||||
rc = PtyRead(pty, data, size);
|
||||
}
|
||||
free(buf);
|
||||
return rc;
|
||||
|
@ -1596,7 +1703,7 @@ static ssize_t OnPtyFdReadv(int fd, const struct iovec *iov, int iovlen) {
|
|||
}
|
||||
}
|
||||
if (size) {
|
||||
if (!(rc = MachinePtyRead(pty, data, size))) {
|
||||
if (!(rc = PtyRead(pty, data, size))) {
|
||||
rc = ReadPtyFdDirect(fd, data, size);
|
||||
}
|
||||
return rc;
|
||||
|
@ -1605,14 +1712,16 @@ static ssize_t OnPtyFdReadv(int fd, const struct iovec *iov, int iovlen) {
|
|||
}
|
||||
}
|
||||
|
||||
static void DrawTerminalOnly(void) {
|
||||
static void DrawDisplayOnly(struct Panel *p) {
|
||||
struct Buffer b;
|
||||
int i, y, yn, xn, tly, tlx, conf;
|
||||
conf = pty->conf & kMachinePtyNocursor;
|
||||
pty->conf |= kMachinePtyNocursor;
|
||||
yn = MIN(tyn, p->bottom - p->top);
|
||||
xn = MIN(txn, p->right - p->left);
|
||||
for (i = 0; i < yn; ++i) {
|
||||
p->lines[i].i = 0;
|
||||
}
|
||||
DrawDisplay(p);
|
||||
memset(&b, 0, sizeof(b));
|
||||
yn = MIN(tyn, pty->yn);
|
||||
xn = MIN(txn, pty->xn);
|
||||
tly = tyn / 2 - yn / 2;
|
||||
tlx = txn / 2 - xn / 2;
|
||||
AppendStr(&b, "\e[0m\e[H");
|
||||
|
@ -1622,24 +1731,21 @@ static void DrawTerminalOnly(void) {
|
|||
for (i = 0; i < tlx; ++i) {
|
||||
AppendChar(&b, ' ');
|
||||
}
|
||||
MachinePtyAppendLine(pty, &b, y - tly);
|
||||
AppendData(&b, p->lines[y - tly].p, p->lines[y - tly].i);
|
||||
}
|
||||
AppendStr(&b, "\e[0m\e[K");
|
||||
}
|
||||
AppendFmt(&b, "\e[%d;%dH", tly + pty->y + 1, tlx + pty->x + 1);
|
||||
write(ttyout, b.p, b.i);
|
||||
free(b.p);
|
||||
pty->conf |= conf;
|
||||
}
|
||||
|
||||
static ssize_t OnPtyFdWritev(int fd, const struct iovec *iov, int iovlen) {
|
||||
int i;
|
||||
size_t size;
|
||||
for (size = i = 0; i < iovlen; ++i) {
|
||||
MachinePtyWrite(pty, iov[i].iov_base, iov[i].iov_len);
|
||||
PtyWrite(pty, iov[i].iov_base, iov[i].iov_len);
|
||||
size += iov[i].iov_len;
|
||||
}
|
||||
if (!tuimode) DrawTerminalOnly();
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -1651,27 +1757,27 @@ static int OnPtyFdTiocgwinsz(int fd, struct winsize *ws) {
|
|||
|
||||
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;
|
||||
if (!(pty->conf & kPtyNocanon)) c->c_iflag |= ICANON;
|
||||
if (!(pty->conf & kPtyNoecho)) c->c_iflag |= ECHO;
|
||||
if (!(pty->conf & kPtyNoopost)) 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;
|
||||
pty->conf &= ~kPtyNocanon;
|
||||
} else {
|
||||
pty->conf |= kMachinePtyNocanon;
|
||||
pty->conf |= kPtyNocanon;
|
||||
}
|
||||
if (c->c_iflag & ECHO) {
|
||||
pty->conf &= ~kMachinePtyNoecho;
|
||||
pty->conf &= ~kPtyNoecho;
|
||||
} else {
|
||||
pty->conf |= kMachinePtyNoecho;
|
||||
pty->conf |= kPtyNoecho;
|
||||
}
|
||||
if (c->c_oflag & OPOST) {
|
||||
pty->conf &= ~kMachinePtyNoopost;
|
||||
pty->conf &= ~kPtyNoopost;
|
||||
} else {
|
||||
pty->conf |= kMachinePtyNoopost;
|
||||
pty->conf |= kPtyNoopost;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1732,14 +1838,13 @@ static void OnSimdException(void) {
|
|||
}
|
||||
|
||||
static void OnUndefinedInstruction(void) {
|
||||
die();
|
||||
strcpy(systemfailure, "UNDEFINED INSTRUCTION");
|
||||
LaunchDebuggerReactively();
|
||||
}
|
||||
|
||||
static void OnDecodeError(void) {
|
||||
strcpy(stpcpy(systemfailure, "DECODE: "),
|
||||
indexdoublenulstring(kXedErrorNames, m->xedd->op.error));
|
||||
IndexDoubleNulString(kXedErrorNames, m->xedd->op.error));
|
||||
LaunchDebuggerReactively();
|
||||
}
|
||||
|
||||
|
@ -1854,15 +1959,15 @@ static void OnVidyaServiceGetMode(void) {
|
|||
}
|
||||
|
||||
static void OnVidyaServiceSetCursorPosition(void) {
|
||||
MachinePtySetY(pty, m->dx[1]);
|
||||
MachinePtySetX(pty, m->dx[0]);
|
||||
PtySetY(pty, m->dx[1]);
|
||||
PtySetX(pty, 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;
|
||||
m->cx[0] = 7 | !!(pty->conf & kPtyNocursor) << 5;
|
||||
}
|
||||
|
||||
static int GetVidyaByte(unsigned char b) {
|
||||
|
@ -1880,7 +1985,7 @@ static void OnVidyaServiceWriteCharacter(void) {
|
|||
p += tpencode(p, 8, GetVidyaByte(m->ax[0]), false);
|
||||
p = stpcpy(p, "\e8");
|
||||
for (i = Read16(m->cx); i--;) {
|
||||
MachinePtyWrite(pty, buf, p - buf);
|
||||
PtyWrite(pty, buf, p - buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1902,7 +2007,7 @@ static void OnVidyaServiceTeletypeOutput(void) {
|
|||
char buf[12];
|
||||
n = FormatCga(m->bx[0], buf);
|
||||
n += tpencode(buf + n, 6, VidyaServiceXlatTeletype(m->ax[0]), false);
|
||||
MachinePtyWrite(pty, buf, n);
|
||||
PtyWrite(pty, buf, n);
|
||||
}
|
||||
|
||||
static void OnVidyaService(void) {
|
||||
|
@ -1933,7 +2038,7 @@ static void OnVidyaService(void) {
|
|||
static void OnKeyboardServiceReadKeyPress(void) {
|
||||
uint8_t b;
|
||||
ssize_t rc;
|
||||
pty->conf |= kMachinePtyBlinkcursor;
|
||||
pty->conf |= kPtyBlinkcursor;
|
||||
if (tuimode) DisableMouseTracking();
|
||||
for (;;) {
|
||||
ReactiveDraw();
|
||||
|
@ -1942,7 +2047,7 @@ static void OnKeyboardServiceReadKeyPress(void) {
|
|||
HandleAppReadInterrupt();
|
||||
}
|
||||
if (tuimode) EnableMouseTracking();
|
||||
pty->conf &= ~kMachinePtyBlinkcursor;
|
||||
pty->conf &= ~kPtyBlinkcursor;
|
||||
ReactiveDraw();
|
||||
if (b == 0x7F) b = '\b';
|
||||
m->ax[0] = b;
|
||||
|
@ -2065,16 +2170,12 @@ static void SetStatus(const char *fmt, ...) {
|
|||
va_list va;
|
||||
int y, x, n;
|
||||
va_start(va, fmt);
|
||||
s = gc(xvasprintf(fmt, va));
|
||||
s = xvasprintf(fmt, va);
|
||||
va_end(va);
|
||||
n = strwidth(s);
|
||||
y = tyn - (n / txn + 1);
|
||||
x = txn / 2 - n / 2;
|
||||
free(statusmessage);
|
||||
statusmessage = xasprintf("\e[0m\e[%d;%dH%s", y + 1, x + 1, s);
|
||||
TtyWriteString(statusmessage);
|
||||
setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {1, 0}}), NULL);
|
||||
statusmessage = s;
|
||||
statusexpires = nowl() + 1;
|
||||
setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {1, 0}}), NULL);
|
||||
}
|
||||
|
||||
static void OnTurbo(void) {
|
||||
|
@ -2201,8 +2302,7 @@ static void Sleep(int ms) {
|
|||
}
|
||||
|
||||
static void OnMouse(char *p) {
|
||||
enum Mouse e;
|
||||
int i, x, y, dy;
|
||||
int e, i, x, y, dy;
|
||||
struct Panel *ep;
|
||||
e = strtol(p, &p, 10);
|
||||
if (*p == ';') ++p;
|
||||
|
@ -2251,7 +2351,10 @@ static void OnMouse(char *p) {
|
|||
static void ReadKeyboard(void) {
|
||||
char buf[64], *p = buf;
|
||||
if (readansi(ttyin, buf, sizeof(buf)) == -1) {
|
||||
if (errno == EINTR) return;
|
||||
if (errno == EINTR) {
|
||||
LOGF("readkeyboard interrupted");
|
||||
return;
|
||||
}
|
||||
FATALF("readkeyboard failed: %s", strerror(errno));
|
||||
}
|
||||
switch (*p++) {
|
||||
|
@ -2384,39 +2487,42 @@ static void Exec(void) {
|
|||
if (!(interrupt = setjmp(m->onhalt))) {
|
||||
if (!(action & CONTINUE) &&
|
||||
(bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) {
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
LOGF("BREAK1 %p", breakpoints.p[bp].addr);
|
||||
tuimode = true;
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
++opcount;
|
||||
CheckFramePointer();
|
||||
ops++;
|
||||
} else {
|
||||
action &= ~CONTINUE;
|
||||
for (;;) {
|
||||
LoadInstruction(m);
|
||||
if ((bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) {
|
||||
LOGF("BREAK2 %p", breakpoints.p[bp].addr);
|
||||
action &= ~(FINISH | NEXT | CONTINUE);
|
||||
tuimode = true;
|
||||
break;
|
||||
}
|
||||
ExecuteInstruction(m);
|
||||
++opcount;
|
||||
KeepGoing:
|
||||
CheckFramePointer();
|
||||
ops++;
|
||||
if (action || breakpoints.i) {
|
||||
if (action & EXIT) {
|
||||
LOGF("EXEC EXIT");
|
||||
break;
|
||||
}
|
||||
if (action & INT) {
|
||||
LOGF("EXEC INT");
|
||||
if (react) {
|
||||
LOGF("REACT");
|
||||
action &= ~(INT | STEP | FINISH | NEXT);
|
||||
tuimode = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) {
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
if (action & ALARM) {
|
||||
DrawDisplayOnly(&pan.display);
|
||||
action &= ~ALARM;
|
||||
}
|
||||
if (action & EXIT) {
|
||||
LOGF("EXEC EXIT");
|
||||
break;
|
||||
}
|
||||
if (action & INT) {
|
||||
LOGF("EXEC INT");
|
||||
if (react) {
|
||||
LOGF("REACT");
|
||||
action &= ~(INT | STEP | FINISH | NEXT);
|
||||
tuimode = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2441,6 +2547,12 @@ static void Tui(void) {
|
|||
if (!(action & FAILURE)) {
|
||||
LoadInstruction(m);
|
||||
UpdateXmmType();
|
||||
if ((action & (FINISH | NEXT | CONTINUE)) &&
|
||||
(bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) {
|
||||
action &= ~(FINISH | NEXT | CONTINUE);
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
m->xedd = (struct XedDecodedInst *)m->icache[0];
|
||||
m->xedd->length = 1;
|
||||
|
@ -2466,14 +2578,17 @@ static void Tui(void) {
|
|||
}
|
||||
if (!(action & CONTINUE) || interactive) {
|
||||
tick = 0;
|
||||
GetDisIndex();
|
||||
SetupDraw();
|
||||
Redraw();
|
||||
}
|
||||
if (action & FAILURE) {
|
||||
LOGF("TUI FAILURE");
|
||||
PrintMessageBox(ttyout, systemfailure, tyn, txn);
|
||||
ReadKeyboard();
|
||||
if (action & INT) {
|
||||
LOGF("TUI INT");
|
||||
LeaveScreen();
|
||||
exit(1);
|
||||
}
|
||||
} else if (!IsExecuting() || (!(action & CONTINUE) && !(action & INT) &&
|
||||
HasPendingKeyboard())) {
|
||||
ReadKeyboard();
|
||||
|
@ -2505,10 +2620,6 @@ static void Tui(void) {
|
|||
break;
|
||||
}
|
||||
if (IsExecuting()) {
|
||||
op = GetDisIndex();
|
||||
ScrollOp(&pan.disassembly, op);
|
||||
VERBOSEF("%s", DisGetLine(dis, m, op));
|
||||
CopyMachineState(&laststate);
|
||||
if (!(action & CONTINUE)) {
|
||||
action &= ~STEP;
|
||||
if (action & NEXT) {
|
||||
|
@ -2529,6 +2640,7 @@ static void Tui(void) {
|
|||
}
|
||||
if (!IsDebugBreak()) {
|
||||
ExecuteInstruction(m);
|
||||
++opcount;
|
||||
if (!(action & CONTINUE) || interactive) {
|
||||
ScrollCode(&pan.code);
|
||||
ScrollStack(&pan.stack);
|
||||
|
@ -2546,7 +2658,6 @@ static void Tui(void) {
|
|||
}
|
||||
KeepGoing:
|
||||
CheckFramePointer();
|
||||
ops++;
|
||||
if (!(action & CONTINUE)) {
|
||||
ScrollOp(&pan.disassembly, GetDisIndex());
|
||||
if ((action & FINISH) && IsRet()) action &= ~FINISH;
|
||||
|
@ -2554,12 +2665,6 @@ static void Tui(void) {
|
|||
action &= ~NEXT;
|
||||
}
|
||||
}
|
||||
if ((action & (FINISH | NEXT | CONTINUE)) &&
|
||||
(bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) {
|
||||
action &= ~(FINISH | NEXT | CONTINUE);
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2611,25 +2716,30 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
setvbuf(g_logfile, xmalloc(PAGESIZE), _IOLBF, PAGESIZE);
|
||||
}
|
||||
|
||||
static int OpenDevTty(void) {
|
||||
return open("/dev/tty", O_RDWR | O_NOCTTY);
|
||||
}
|
||||
|
||||
static void AddHostFd(int fd) {
|
||||
int i = m->fds.i++;
|
||||
CHECK_NE(-1, (m->fds.p[i].fd = fd));
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
}
|
||||
|
||||
int Emulator(int argc, char *argv[]) {
|
||||
void *code;
|
||||
int rc, fd;
|
||||
codepath = argv[optind++];
|
||||
pty = MachinePtyNew();
|
||||
m->fds.p = xcalloc((m->fds.n = 8), sizeof(struct MachineFd));
|
||||
Restart:
|
||||
action = 0;
|
||||
LoadProgram(m, codepath, argv + optind, environ, elf);
|
||||
m->fds.i = 3;
|
||||
m->fds.p[0].fd = STDIN_FILENO;
|
||||
m->fds.p[0].cb = &kMachineFdCbHost;
|
||||
m->fds.p[1].fd = STDOUT_FILENO;
|
||||
m->fds.p[1].cb = &kMachineFdCbHost;
|
||||
m->fds.p[2].fd = STDERR_FILENO;
|
||||
m->fds.p[2].cb = &kMachineFdCbHost;
|
||||
AddHostFd(STDIN_FILENO);
|
||||
AddHostFd(STDOUT_FILENO);
|
||||
AddHostFd(STDERR_FILENO);
|
||||
if (tuimode) {
|
||||
ttyin = isatty(0) ? 0 : open("/dev/tty", O_RDWR | O_NOCTTY);
|
||||
ttyout = isatty(1) ? 1 : open("/dev/tty", O_RDWR | O_NOCTTY);
|
||||
ttyin = isatty(STDIN_FILENO) ? STDIN_FILENO : OpenDevTty();
|
||||
ttyout = isatty(STDOUT_FILENO) ? STDOUT_FILENO : OpenDevTty();
|
||||
} else {
|
||||
ttyin = -1;
|
||||
ttyout = -1;
|
||||
|
@ -2640,18 +2750,9 @@ Restart:
|
|||
tyn = 24;
|
||||
txn = 80;
|
||||
GetTtySize(ttyout);
|
||||
if (isatty(0)) {
|
||||
m->fds.p[0].fd = 0;
|
||||
m->fds.p[0].cb = &kMachineFdCbPty;
|
||||
}
|
||||
if (isatty(1)) {
|
||||
m->fds.p[1].fd = 1;
|
||||
m->fds.p[1].cb = &kMachineFdCbPty;
|
||||
}
|
||||
if (isatty(2)) {
|
||||
m->fds.p[2].fd = 2;
|
||||
m->fds.p[2].cb = &kMachineFdCbPty;
|
||||
}
|
||||
if (isatty(STDIN_FILENO)) m->fds.p[STDIN_FILENO].cb = &kMachineFdCbPty;
|
||||
if (isatty(STDOUT_FILENO)) m->fds.p[STDOUT_FILENO].cb = &kMachineFdCbPty;
|
||||
if (isatty(STDERR_FILENO)) m->fds.p[STDERR_FILENO].cb = &kMachineFdCbPty;
|
||||
}
|
||||
while (!(action & EXIT)) {
|
||||
if (!tuimode) {
|
||||
|
@ -2669,7 +2770,7 @@ Restart:
|
|||
if (printstats) {
|
||||
fprintf(stderr, "taken: %,ld\n", taken);
|
||||
fprintf(stderr, "ntaken: %,ld\n", ntaken);
|
||||
fprintf(stderr, "ops: %,ld\n", ops);
|
||||
fprintf(stderr, "ops: %,ld\n", opcount);
|
||||
}
|
||||
munmap(elf->ehdr, elf->size);
|
||||
DisFree(dis);
|
||||
|
@ -2682,12 +2783,13 @@ static void OnlyRunOnFirstCpu(void) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!NoDebug()) showcrashreports();
|
||||
pty = NewPty();
|
||||
m = NewMachine();
|
||||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
speed = 16;
|
||||
SetXmmSize(2);
|
||||
SetXmmDisp(kXmmHex);
|
||||
if (!NoDebug()) showcrashreports();
|
||||
/* OnlyRunOnFirstCpu(); */
|
||||
if ((colorize = cancolor())) {
|
||||
g_high.keyword = 155;
|
||||
g_high.reg = 215;
|
||||
|
@ -2697,6 +2799,7 @@ int main(int argc, char *argv[]) {
|
|||
g_high.quote = 215;
|
||||
}
|
||||
GetOpts(argc, argv);
|
||||
xsigaction(SIGALRM, OnSigAlarm, 0, 0, 0);
|
||||
if (optind == argc) PrintUsage(EX_USAGE, stderr);
|
||||
return Emulator(argc, argv);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/color.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
|
|
|
@ -58,6 +58,14 @@ o/$(MODE)/tool/build/emubin/%.elf: \
|
|||
$(ELF)
|
||||
@$(ELFLINK)
|
||||
|
||||
o/$(MODE)/tool/build/emubin/lisp.elf: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
$(TOOL_BUILD_EMUBIN_A) \
|
||||
o/$(MODE)/tool/build/emubin/lisp.o \
|
||||
o/$(MODE)/tool/build/emubin/lispelf.o \
|
||||
$(ELF)
|
||||
@$(ELFLINK)
|
||||
|
||||
o/dbg/tool/build/emubin/lisp.real.com.dbg: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
$(TOOL_BUILD_EMUBIN_A) \
|
||||
|
@ -73,6 +81,13 @@ o/$(MODE)/tool/build/emubin/lisp.bin.dbg: \
|
|||
tool/build/emubin/lisp.lds
|
||||
@$(ELFLINK) -z max-page-size=0x10
|
||||
|
||||
o/$(MODE)/tool/build/emubin/love.bin.dbg: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
o/$(MODE)/tool/build/emubin/love.o \
|
||||
o/$(MODE)/tool/build/emubin/lispstart.o \
|
||||
tool/build/emubin/lisp.lds
|
||||
@$(ELFLINK) -z max-page-size=0x10
|
||||
|
||||
o/tiny/tool/build/emubin/spiral.bin.dbg: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
o/tiny/tool/build/emubin/spiral.real.o
|
||||
|
|
|
@ -18,15 +18,13 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/emubin/lisp.h"
|
||||
|
||||
#define TRACE 0 // print eval input output
|
||||
#define RETRO 1 // auto capitalize input
|
||||
#define ERRORS 1 // print messages or undefined behavior
|
||||
#define DELETE 1 // allow backspace to rub out symbol
|
||||
#define QUOTES 1 // allow 'X shorthand (QUOTE X)
|
||||
#define MUTABLE 0 // allow setting globals
|
||||
#define PROMPT 1 // show repl prompt
|
||||
#define WORD short
|
||||
#define WORDS 8192
|
||||
#define TRACE 0 // print eval input output
|
||||
#define RETRO 0 // auto capitalize input
|
||||
#define DELETE 0 // allow backspace to rub out symbol
|
||||
#define QUOTES 0 // allow 'X shorthand (QUOTE X)
|
||||
#define PROMPT 0 // show repl prompt
|
||||
#define WORD short
|
||||
#define WORDS 8192
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ The LISP Challenge § LISP Machine ─╬─│┼
|
||||
|
@ -36,25 +34,16 @@
|
|||
#define CONS 1
|
||||
|
||||
#define NIL 0
|
||||
#define ATOM_T 8
|
||||
#define ATOM_QUOTE 12
|
||||
#define ATOM_ATOM 24
|
||||
#define ATOM_EQ 34
|
||||
#define ATOM_COND 40
|
||||
#define ATOM_CAR 50
|
||||
#define ATOM_CDR 58
|
||||
#define ATOM_CONS 66
|
||||
#define ATOM_LAMBDA 76
|
||||
#define ATOM_SET 90
|
||||
|
||||
#define Quote(x) List(ATOM_QUOTE, x)
|
||||
#define List(x, y) Cons(x, Cons(y, NIL))
|
||||
#define Caar(x) Car(Car(x)) // ((A B C D) (E F G) H I) → A
|
||||
#define Cdar(x) Cdr(Car(x)) // ((A B C D) (E F G) H I) → (B C D)
|
||||
#define Cadar(x) Cadr(Car(x)) // ((A B C D) (E F G) H I) → B
|
||||
#define Caddar(x) Caddr(Car(x)) // ((A B C D) (E F G) H I) → C
|
||||
#define Cadr(x) Car(Cdr(x)) // ((A B C D) (E F G) H I) → (E F G)
|
||||
#define Caddr(x) Cadr(Cdr(x)) // ((A B C D) (E F G) H I) → H
|
||||
#define UNDEFINED 8
|
||||
#define ATOM_T 30
|
||||
#define ATOM_QUOTE 34
|
||||
#define ATOM_ATOM 46
|
||||
#define ATOM_EQ 56
|
||||
#define ATOM_COND 62
|
||||
#define ATOM_CAR 72
|
||||
#define ATOM_CDR 80
|
||||
#define ATOM_CONS 88
|
||||
#define ATOM_LAMBDA 98
|
||||
|
||||
#define BOOL(x) ((x) ? ATOM_T : NIL)
|
||||
#define VALUE(x) ((x) >> 1)
|
||||
|
@ -67,7 +56,6 @@ struct Lisp {
|
|||
WORD globals;
|
||||
WORD index;
|
||||
char token[128];
|
||||
long jb[8];
|
||||
char str[WORDS];
|
||||
};
|
||||
|
||||
|
@ -75,6 +63,7 @@ _Static_assert(sizeof(struct Lisp) <= 0x7c00 - 0x600,
|
|||
"LISP Machine too large for real mode");
|
||||
|
||||
_Alignas(char) const char kSymbols[] = "NIL\0"
|
||||
"*UNDEFINED\0"
|
||||
"T\0"
|
||||
"QUOTE\0"
|
||||
"ATOM\0"
|
||||
|
@ -83,8 +72,7 @@ _Alignas(char) const char kSymbols[] = "NIL\0"
|
|||
"CAR\0"
|
||||
"CDR\0"
|
||||
"CONS\0"
|
||||
"LAMBDA\0"
|
||||
"SET\0";
|
||||
"LAMBDA\0";
|
||||
|
||||
#ifdef __REAL_MODE__
|
||||
static struct Lisp *const q;
|
||||
|
@ -112,6 +100,10 @@ static void SetupSyntax(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void SetupBuiltins(void) {
|
||||
CopyMemory(q->str, kSymbols, sizeof(kSymbols));
|
||||
}
|
||||
|
||||
static inline WORD Car(long x) {
|
||||
return PEEK_ARRAY(q, mem, VALUE(x), 0);
|
||||
}
|
||||
|
@ -136,23 +128,16 @@ static WORD Cons(WORD car, WORD cdr) {
|
|||
return cell;
|
||||
}
|
||||
|
||||
static void SetupBuiltins(void) {
|
||||
CopyMemory(q->str, kSymbols, sizeof(kSymbols));
|
||||
q->mem[0] = PTR(2);
|
||||
q->globals = PTR(0);
|
||||
q->index = 4;
|
||||
}
|
||||
|
||||
static char *StpCpy(char *d, char *s) {
|
||||
char c;
|
||||
do {
|
||||
c = LODS(s); /* a.k.a. c = *s++; */
|
||||
STOS(d, c); /* a.k.a. *d++ = c; */
|
||||
c = LODS(s); // a.k.a. c = *s++
|
||||
STOS(d, c); // a.k.a. *d++ = c
|
||||
} while (c);
|
||||
return d;
|
||||
}
|
||||
|
||||
WORD Intern(char *s) {
|
||||
static WORD Intern(char *s) {
|
||||
int j, cx;
|
||||
char c, *z, *t;
|
||||
z = q->str;
|
||||
|
@ -175,7 +160,7 @@ WORD Intern(char *s) {
|
|||
return OBJECT(ATOM, SUB((long)z, q->str));
|
||||
}
|
||||
|
||||
forceinline unsigned char XlatSyntax(unsigned char b) {
|
||||
static unsigned char XlatSyntax(unsigned char b) {
|
||||
return PEEK_ARRAY(q, syntax, b, 0);
|
||||
}
|
||||
|
||||
|
@ -207,17 +192,19 @@ static int GetChar(void) {
|
|||
|
||||
static void GetToken(void) {
|
||||
char *t;
|
||||
unsigned char b;
|
||||
unsigned char b, x;
|
||||
b = q->look;
|
||||
t = q->token;
|
||||
while (XlatSyntax(b) == ' ') {
|
||||
for (;;) {
|
||||
x = XlatSyntax(b);
|
||||
if (x != ' ') break;
|
||||
b = GetChar();
|
||||
}
|
||||
if (XlatSyntax(b)) {
|
||||
if (x) {
|
||||
STOS(t, b);
|
||||
b = GetChar();
|
||||
} else {
|
||||
while (b && !XlatSyntax(b)) {
|
||||
while (b && !x) {
|
||||
if (!DELETE || b != '\b') {
|
||||
STOS(t, b);
|
||||
} else if (t > q->token) {
|
||||
|
@ -225,6 +212,7 @@ static void GetToken(void) {
|
|||
if (t > q->token) --t;
|
||||
}
|
||||
b = GetChar();
|
||||
x = XlatSyntax(b);
|
||||
}
|
||||
}
|
||||
STOS(t, 0);
|
||||
|
@ -236,6 +224,18 @@ static WORD ConsumeObject(void) {
|
|||
return GetObject();
|
||||
}
|
||||
|
||||
static WORD Cadr(long x) {
|
||||
return Car(Cdr(x)); // ((A B C D) (E F G) H I) → (E F G)
|
||||
}
|
||||
|
||||
static WORD List(long x, long y) {
|
||||
return Cons(x, Cons(y, NIL));
|
||||
}
|
||||
|
||||
static WORD Quote(long x) {
|
||||
return List(ATOM_QUOTE, x);
|
||||
}
|
||||
|
||||
static WORD GetQuote(void) {
|
||||
return Quote(ConsumeObject());
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ static void PrintList(long x) {
|
|||
PrintChar('(');
|
||||
PrintObject(Car(x));
|
||||
while ((x = Cdr(x))) {
|
||||
if (TYPE(x) == CONS) {
|
||||
if (!ISATOM(x)) {
|
||||
PrintChar(' ');
|
||||
PrintObject(Car(x));
|
||||
} else {
|
||||
|
@ -311,7 +311,7 @@ static void PrintList(long x) {
|
|||
}
|
||||
|
||||
static void PrintObject(long x) {
|
||||
if (TYPE(x) == ATOM) {
|
||||
if (ISATOM(x)) {
|
||||
PrintAtom(x);
|
||||
} else {
|
||||
PrintList(x);
|
||||
|
@ -323,42 +323,38 @@ static void Print(long i) {
|
|||
PrintString("\r\n");
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void Reset(void) {
|
||||
longjmp(q->jb, 1);
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void OnArity(void) {
|
||||
PrintString("ARITY!\n");
|
||||
Reset();
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void OnUndefined(long x) {
|
||||
PrintString("UNDEF! ");
|
||||
Print(x);
|
||||
Reset();
|
||||
}
|
||||
|
||||
#if !ERRORS
|
||||
#define OnArity() __builtin_unreachable()
|
||||
#define OnUndefined(x) __builtin_unreachable()
|
||||
#endif
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ The LISP Challenge § Bootstrap John McCarthy's Metacircular Evaluator ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
static WORD Atom(long x) {
|
||||
return BOOL(TYPE(x) == ATOM);
|
||||
return BOOL(ISATOM(x));
|
||||
}
|
||||
|
||||
static WORD Null(long x) {
|
||||
return BOOL(!x);
|
||||
}
|
||||
|
||||
static WORD Eq(long x, long y) {
|
||||
WORD Eq(long x, long y) {
|
||||
return BOOL(x == y);
|
||||
}
|
||||
|
||||
static WORD Caar(long x) {
|
||||
return Car(Car(x)); // ((A B C D) (E F G) H I) → A
|
||||
}
|
||||
|
||||
static WORD Cdar(long x) {
|
||||
return Cdr(Car(x)); // ((A B C D) (E F G) H I) → (B C D)
|
||||
}
|
||||
|
||||
static WORD Cadar(long x) {
|
||||
return Cadr(Car(x)); // ((A B C D) (E F G) H I) → B
|
||||
}
|
||||
|
||||
static WORD Caddr(long x) {
|
||||
return Cadr(Cdr(x)); // ((A B C D) (E F G) H I) → H
|
||||
}
|
||||
|
||||
static WORD Caddar(long x) {
|
||||
return Caddr(Car(x)); // ((A B C D) (E F G) H I) → C
|
||||
}
|
||||
|
||||
static WORD Arg1(long e, long a) {
|
||||
return Eval(Cadr(e), a);
|
||||
}
|
||||
|
@ -368,37 +364,36 @@ static WORD Arg2(long e, long a) {
|
|||
}
|
||||
|
||||
static WORD Append(long x, long y) {
|
||||
return Null(x) ? y : Cons(Car(x), Append(Cdr(x), y));
|
||||
return x ? Cons(Car(x), Append(Cdr(x), y)) : y;
|
||||
}
|
||||
|
||||
static WORD Evcon(long c, long a) {
|
||||
return Eval(Caar(c), a) ? Eval(Cadar(c), a) : Evcon(Cdr(c), a);
|
||||
}
|
||||
|
||||
static WORD Evlis(long m, long a) {
|
||||
return m ? Cons(Eval(Car(m), a), Evlis(Cdr(m), a)) : NIL;
|
||||
static WORD Bind(long v, long a, long e) {
|
||||
return v ? Cons(Cons(Car(v), Eval(Car(a), e)), Bind(Cdr(v), Cdr(a), e)) : e;
|
||||
}
|
||||
|
||||
static WORD Assoc(long x, long y) {
|
||||
if (!y) OnUndefined(x);
|
||||
return Eq(Caar(y), x) ? Cdar(y) : Assoc(x, Cdr(y));
|
||||
return y ? Eq(Caar(y), x) ? Cdar(y) : Assoc(x, Cdr(y)) : NIL;
|
||||
}
|
||||
|
||||
static WORD Pair(long x, long y) {
|
||||
if (Null(x) && Null(y)) {
|
||||
if (Atom(x) || Atom(y)) {
|
||||
return NIL;
|
||||
} else if (!Atom(x) && !Atom(y)) {
|
||||
return Cons(Cons(Car(x), Car(y)), Pair(Cdr(x), Cdr(y)));
|
||||
} else {
|
||||
OnArity();
|
||||
return Cons(Cons(Car(x), Car(y)), Pair(Cdr(x), Cdr(y)));
|
||||
}
|
||||
}
|
||||
|
||||
static WORD Evaluate(long e, long a) {
|
||||
__attribute__((__noinline__)) static WORD Evaluate(long e, long a) {
|
||||
if (Atom(e)) {
|
||||
return Assoc(e, a);
|
||||
} else if (Atom(Car(e))) {
|
||||
switch (Car(e)) {
|
||||
case NIL:
|
||||
return UNDEFINED;
|
||||
case ATOM_QUOTE:
|
||||
return Cadr(e);
|
||||
case ATOM_ATOM:
|
||||
|
@ -413,17 +408,13 @@ static WORD Evaluate(long e, long a) {
|
|||
return Cdr(Arg1(e, a));
|
||||
case ATOM_CONS:
|
||||
return Cons(Arg1(e, a), Arg2(e, a));
|
||||
#if MUTABLE
|
||||
case ATOM_SET:
|
||||
return Cdar(Set(a, Cons(Arg1(e, a), Arg2(e, a)), Cons(Car(a), Cdr(a))));
|
||||
#endif
|
||||
default:
|
||||
return Eval(Cons(Assoc(Car(e), a), Evlis(Cdr(e), a)), a);
|
||||
return Eval(Cons(Assoc(Car(e), a), Cdr(e)), a);
|
||||
}
|
||||
} else if (Eq(Caar(e), ATOM_LAMBDA)) {
|
||||
return Eval(Caddar(e), Append(Pair(Cadar(e), Evlis(Cdr(e), a)), a));
|
||||
return Eval(Caddar(e), Bind(Cadar(e), Cdr(e), a));
|
||||
} else {
|
||||
OnUndefined(Caar(e));
|
||||
return UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,9 +439,6 @@ static WORD Eval(long e, long a) {
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
void Repl(void) {
|
||||
#if ERRORS
|
||||
setjmp(q->jb);
|
||||
#endif
|
||||
for (;;) {
|
||||
#if PROMPT
|
||||
PrintString("* ");
|
||||
|
@ -460,7 +448,7 @@ void Repl(void) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/* RawMode(); */
|
||||
RawMode();
|
||||
SetupSyntax();
|
||||
SetupBuiltins();
|
||||
#if PROMPT
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
#define CompilerBarrier() asm volatile("" ::: "memory");
|
||||
|
||||
#define TYPE(x) /* a.k.a. x&1 */ \
|
||||
({ \
|
||||
char IsAtom; \
|
||||
asm("test%z1\t$1,%1" : "=@ccnz"(IsAtom) : "Qm"((char)x)); \
|
||||
IsAtom; \
|
||||
#define ISATOM(x) /* a.k.a. !(x&1) */ \
|
||||
({ \
|
||||
_Bool IsAtom; \
|
||||
asm("test%z1\t$1,%1" : "=@ccz"(IsAtom) : "Qm"((char)x)); \
|
||||
IsAtom; \
|
||||
})
|
||||
|
||||
#define OBJECT(t, v) /* a.k.a. v<<1|t */ \
|
||||
|
@ -112,9 +112,6 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
int setjmp(void *) __attribute__((__returns_twice__));
|
||||
int longjmp(void *, int) __attribute__((__noreturn__));
|
||||
|
||||
static inline void *SetMemory(void *di, int al, unsigned long cx) {
|
||||
asm("rep stosb"
|
||||
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||
|
@ -170,6 +167,7 @@ static int ReadChar(void) {
|
|||
int c;
|
||||
#ifdef __REAL_MODE__
|
||||
asm volatile("int\t$0x16" : "=a"(c) : "0"(0) : "memory");
|
||||
c &= 0xff;
|
||||
#else
|
||||
static int buf;
|
||||
asm volatile("syscall"
|
||||
|
|
|
@ -29,7 +29,7 @@ SECTIONS {
|
|||
. = 0x1fe;
|
||||
SHORT(0xaa55);
|
||||
*(.text .text.*)
|
||||
BYTE(0x90);
|
||||
/*BYTE(0x90);*/
|
||||
_etext = .;
|
||||
. = ALIGN(512);
|
||||
}
|
||||
|
|
|
@ -1,30 +1,105 @@
|
|||
;; (SET 'APPLY '(LAMBDA (E ARGS)
|
||||
;; ((LAMBDA (APPQ)
|
||||
;; (CONS ))
|
||||
;; '(LAMBDA (M)
|
||||
;; (COND ((EQ M 'NIL) 'NIL)
|
||||
;; ('T (CONS (QUOTE (CAR M))
|
||||
;; (APPQ (CONS 'QUOTE (CDR M))))))))))
|
||||
;; (SET 'LIST '(LAMBDA (X Y) (CONS X (CONS Y 'NIL))))
|
||||
;; (SET 'AND '(LAMBDA (P Q) (COND ((EQ P 'T) Q) ('T 'F))))
|
||||
;; (SET 'OR '(LAMBDA (P Q) (COND ((EQ P 'T) 'T) ('T Q))))
|
||||
;; (SET 'NOT '(LAMBDA (P) (COND ((EQ P 'F) 'T) ('T 'T))))
|
||||
;; (SET 'IMPLIES '(LAMBDA (P Q) (COND ((EQ P 'T) Q) ('T 'T))))
|
||||
;; (setq lisp-indent-function 'common-lisp-indent-function)
|
||||
;; (paredit-mode)
|
||||
|
||||
((LAMBDA (CALL MKQUOT NULL AND APPEND KEYS VALS E A)
|
||||
(CALL (CONS (CONS (QUOTE LAMBDA) (CONS (KEYS (QUOTE A)) (CONS E NIL))) (VALS (QUOTE A)))))
|
||||
(QUOTE (LAMBDA (X) (X)))
|
||||
(QUOTE (LAMBDA (X) (CONS (QUOTE QUOTE) (CONS X NIL))))
|
||||
(QUOTE (LAMBDA (P Q) (COND ((EQ P (QUOTE T)) Q) ((QUOTE T) (QUOTE F)))))
|
||||
(QUOTE (LAMBDA (X) (AND (QUOTE (ATOM X)) (QUOTE (EQ X NIL)))))
|
||||
(QUOTE (LAMBDA (X Y) (COND ((EQ X NIL) Y) ((QUOTE T) (CONS (CAR X) (APPEND (QUOTE (CDR X)) (QUOTE Y)))))))
|
||||
(QUOTE (LAMBDA (A) (COND ((EQ A NIL) NIL) ((QUOTE T) (CONS (CAR (CAR A)) (KEYS (QUOTE (CDR A))))))))
|
||||
(QUOTE (LAMBDA (A) (COND ((EQ A NIL) NIL) ((QUOTE T) (CONS (MKQUOT (QUOTE (CDR (CAR A)))) (VALS (QUOTE (CDR A))))))))
|
||||
(QUOTE (AND (QUOTE A) (QUOTE C)))
|
||||
(CONS (CONS (QUOTE A) (QUOTE B)) (CONS (CONS (QUOTE C) (QUOTE D)) NIL)))
|
||||
;; ________
|
||||
;; /_ __/ /_ ___
|
||||
;; / / / __ \/ _ \
|
||||
;; / / / / / / __/
|
||||
;; /_/ /_/ /_/\___/
|
||||
;; __ _________ ____ ________ ____
|
||||
;; / / / _/ ___// __ \ / ____/ /_ ____ _/ / /__ ____ ____ ____
|
||||
;; / / / / \__ \/ /_/ / / / / __ \/ __ `/ / / _ \/ __ \/ __ `/ _ \
|
||||
;; / /____/ / ___/ / ____/ / /___/ / / / /_/ / / / __/ / / / /_/ / __/
|
||||
;; /_____/___//____/_/ \____/_/ /_/\__,_/_/_/\___/_/ /_/\__, /\___/
|
||||
;; /____/
|
||||
;;
|
||||
;; THE LISP CHALLENGE
|
||||
;;
|
||||
;; PICK YOUR FAVORITE PROGRAMMING LANGUAGE
|
||||
;; IMPLEMENT THE TINIEST POSSIBLE LISP MACHINE THAT
|
||||
;; BOOTSTRAPS JOHN MCCARTHY'S METACIRCULAR EVALUATOR
|
||||
;; WINNING IS DEFINED BY LINES OF CODE FOR SCRIPTING LANGUAGES
|
||||
;; WINNING IS DEFINED BY BINARY FOOTPRINT FOR COMPILED LANGUAGES
|
||||
;;
|
||||
;; @SEE LISP FROM NOTHING; NILS M. HOLM; LULU PRESS, INC. 2020
|
||||
;; @SEE RECURSIVE FUNCTIONS OF SYMBOLIC EXPRESSIONS AND THEIR
|
||||
;; COMPUTATION BY MACHINE, PART I; JOHN MCCARTHY, MASSACHUSETTS
|
||||
;; INSTITUTE OF TECHNOLOGY, CAMBRIDGE, MASS. APRIL 1960
|
||||
|
||||
((LAMBDA (FF X) (FF 'X))
|
||||
'(LAMBDA (X)
|
||||
(COND ((ATOM X) X)
|
||||
((QUOTE T) (FF '(CAR X)))))
|
||||
'((A) B C))
|
||||
;; NIL ATOM
|
||||
;; ABSENCE OF VALUE
|
||||
NIL
|
||||
|
||||
;; CONS CELL
|
||||
;; BUILDING BLOCK OF DATA STRUCTURES
|
||||
(CONS NIL NIL)
|
||||
|
||||
;; REFLECTION
|
||||
;; EVERYTHING IS AN ATOM OR NOT AN ATOM
|
||||
(ATOM NIL)
|
||||
(ATOM (CONS NIL NIL))
|
||||
|
||||
;; QUOTING
|
||||
;; CODE IS DATA AND DATA IS CODE
|
||||
(QUOTE (CONS NIL NIL))
|
||||
(CONS (QUOTE CONS) (CONS NIL (CONS NIL NIL)))
|
||||
|
||||
;; LOGIC
|
||||
;; LAW OF IDENTITY VIA STRING INTERNING
|
||||
(EQ (QUOTE A) (QUOTE A))
|
||||
|
||||
;; FIND FIRST ATOM IN TREE
|
||||
;; RECURSIVE CONDITIONAL FUNCTION BINDING
|
||||
((LAMBDA (FF X) (FF X))
|
||||
(QUOTE (LAMBDA (X)
|
||||
(COND ((ATOM X) X)
|
||||
((QUOTE T) (FF (CAR X))))))
|
||||
(QUOTE ((A) B C)))
|
||||
|
||||
;; LISP IMPLEMENTED IN LISP
|
||||
;; USED TO EVALUATE FIND FIRST ATOM IN TREE
|
||||
;; REQUIRES CONS CAR CDR QUOTE ATOM EQ LAMBDA COND
|
||||
;; FIXES BUGS FROM JOHN MCCARTHY PAPER AND MORE MINIMAL
|
||||
((LAMBDA (ASSOC EVCON BIND APPEND EVAL)
|
||||
(EVAL (QUOTE ((LAMBDA (FF X) (FF X))
|
||||
(QUOTE (LAMBDA (X)
|
||||
(COND ((ATOM X) X)
|
||||
((QUOTE T) (FF (CAR X))))))
|
||||
(QUOTE ((A) B C))))
|
||||
NIL))
|
||||
(QUOTE (LAMBDA (X E)
|
||||
(COND ((EQ E NIL) NIL)
|
||||
((EQ X (CAR (CAR E))) (CDR (CAR E)))
|
||||
((QUOTE T) (ASSOC X (CDR E))))))
|
||||
(QUOTE (LAMBDA (C E)
|
||||
(COND ((EVAL (CAR (CAR C)) E) (EVAL (CAR (CDR (CAR C))) E))
|
||||
((QUOTE T) (EVCON (CDR C) E)))))
|
||||
(QUOTE (LAMBDA (V A E)
|
||||
(COND ((EQ V NIL) E)
|
||||
((QUOTE T) (CONS (CONS (CAR V) (EVAL (CAR A) E))
|
||||
(BIND (CDR V) (CDR A) E))))))
|
||||
(QUOTE (LAMBDA (A B)
|
||||
(COND ((EQ A NIL) B)
|
||||
((QUOTE T) (CONS (CAR A) (APPEND (CDR A) B))))))
|
||||
(QUOTE (LAMBDA (E A)
|
||||
(COND
|
||||
((ATOM E) (ASSOC E A))
|
||||
((ATOM (CAR E))
|
||||
(COND
|
||||
((EQ (CAR E) NIL) (QUOTE *UNDEFINED))
|
||||
((EQ (CAR E) (QUOTE QUOTE)) (CAR (CDR E)))
|
||||
((EQ (CAR E) (QUOTE ATOM)) (ATOM (EVAL (CAR (CDR E)) A)))
|
||||
((EQ (CAR E) (QUOTE EQ)) (EQ (EVAL (CAR (CDR E)) A)
|
||||
(EVAL (CAR (CDR (CDR E))) A)))
|
||||
((EQ (CAR E) (QUOTE CAR)) (CAR (EVAL (CAR (CDR E)) A)))
|
||||
((EQ (CAR E) (QUOTE CDR)) (CDR (EVAL (CAR (CDR E)) A)))
|
||||
((EQ (CAR E) (QUOTE CONS)) (CONS (EVAL (CAR (CDR E)) A)
|
||||
(EVAL (CAR (CDR (CDR E))) A)))
|
||||
((EQ (CAR E) (QUOTE COND)) (EVCON (CDR E) A))
|
||||
((EQ (CAR E) (QUOTE LABEL)) (EVAL (CAR (CDR (CDR E)))
|
||||
(APPEND (CAR (CDR E)) A)))
|
||||
((EQ (CAR E) (QUOTE LAMBDA)) E)
|
||||
((QUOTE T) (EVAL (CONS (EVAL (CAR E) A) (CDR E)) A))))
|
||||
((EQ (CAR (CAR E)) (QUOTE LAMBDA))
|
||||
(EVAL (CAR (CDR (CDR (CAR E))))
|
||||
(BIND (CAR (CDR (CAR E))) (CDR E) A)))))))
|
||||
|
|
23
tool/build/emubin/lispelf.S
Normal file
23
tool/build/emubin/lispelf.S
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
_start: jmp main
|
||||
.endfn _start,globl
|
|
@ -49,29 +49,3 @@ _begin: push %cs
|
|||
jmp main
|
||||
.type _begin,@function
|
||||
.size _begin,.-_begin
|
||||
|
||||
.section .start.setjmp,"ax",@progbits
|
||||
setjmp: mov %sp,%ax
|
||||
stosw
|
||||
xchg %ax,%si
|
||||
movsw %ss:(%si),(%di)
|
||||
mov %bp,%ax
|
||||
stosw
|
||||
ret $6
|
||||
.type setjmp,@function
|
||||
.size setjmp,.-setjmp
|
||||
.globl setjmp
|
||||
.previous
|
||||
|
||||
.section .start.longjmp,"ax",@progbits
|
||||
longjmp:
|
||||
mov (%di),%sp
|
||||
mov 2(%di),%dx
|
||||
mov 4(%di),%bp
|
||||
pop %ax
|
||||
mov %si,%ax
|
||||
jmp *%dx
|
||||
.type longjmp,@function
|
||||
.size longjmp,.-longjmp
|
||||
.globl longjmp
|
||||
.previous
|
||||
|
|
|
@ -37,15 +37,6 @@ const aluop_f kBsu[8][4] = {
|
|||
{Shl8, Shl16, Shl32, Shl64}, {Sar8, Sar16, Sar32, Sar64},
|
||||
};
|
||||
|
||||
int64_t AluFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf,
|
||||
uint32_t sf) {
|
||||
*f &= ~(1u << FLAGS_CF | 1u << FLAGS_ZF | 1u << FLAGS_SF | 1u << FLAGS_OF |
|
||||
1u << FLAGS_AF | 0xFF000000u);
|
||||
*f |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF |
|
||||
af << FLAGS_AF | (x & 0xFF) << 24;
|
||||
return x;
|
||||
}
|
||||
|
||||
int64_t AluFlags8(uint8_t z, uint32_t af, uint32_t *f, uint32_t of,
|
||||
uint32_t cf) {
|
||||
return AluFlags(z, af, f, of, cf, z >> 7);
|
||||
|
|
|
@ -108,7 +108,6 @@ int64_t Rcl64(uint64_t, uint64_t, uint32_t *);
|
|||
|
||||
uint64_t BsuDoubleShift(int, uint64_t, uint64_t, uint8_t, bool, uint32_t *);
|
||||
|
||||
int64_t AluFlags(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t, uint32_t);
|
||||
int64_t AluFlags8(uint8_t, uint32_t, uint32_t *, uint32_t, uint32_t);
|
||||
int64_t AluFlags16(uint16_t, uint32_t, uint32_t *, uint32_t, uint32_t);
|
||||
int64_t AluFlags32(uint32_t, uint32_t, uint32_t *, uint32_t, uint32_t);
|
||||
|
|
|
@ -49,16 +49,17 @@ void AppendWide(struct Buffer *b, wint_t wc) {
|
|||
} while (wb);
|
||||
}
|
||||
|
||||
void AppendFmt(struct Buffer *b, const char *fmt, ...) {
|
||||
int size;
|
||||
int AppendFmt(struct Buffer *b, const char *fmt, ...) {
|
||||
int bytes;
|
||||
char *tmp;
|
||||
va_list va;
|
||||
tmp = NULL;
|
||||
va_start(va, fmt);
|
||||
size = vasprintf(&tmp, fmt, va);
|
||||
bytes = vasprintf(&tmp, fmt, va);
|
||||
va_end(va);
|
||||
if (size != -1) AppendData(b, tmp, size);
|
||||
if (bytes != -1) AppendData(b, tmp, bytes);
|
||||
free(tmp);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,7 +12,7 @@ void AppendChar(struct Buffer *, char);
|
|||
void AppendData(struct Buffer *, char *, size_t);
|
||||
void AppendStr(struct Buffer *, const char *);
|
||||
void AppendWide(struct Buffer *, wint_t);
|
||||
void AppendFmt(struct Buffer *, const char *, ...);
|
||||
int AppendFmt(struct Buffer *, const char *, ...);
|
||||
ssize_t WriteBuffer(struct Buffer *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -68,6 +68,10 @@ $(TOOL_BUILD_LIB_A_OBJS): \
|
|||
-fsanitize=address
|
||||
endif
|
||||
|
||||
o/$(MODE)/tool/build/lib/memory-gcc.asm: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-fsanitize=address
|
||||
|
||||
o/$(MODE)/tool/build/lib/ssefloat.o: \
|
||||
TARGET_ARCH += \
|
||||
-msse3
|
||||
|
|
|
@ -31,8 +31,8 @@ void OpCpuid(struct Machine *m, uint32_t rde) {
|
|||
case 0x80000000:
|
||||
ax = 7;
|
||||
bx = 'G' | 'e' << 8 | 'n' << 16 | 'u' << 24;
|
||||
cx = 'i' | 'n' << 8 | 'e' << 16 | 'C' << 24;
|
||||
dx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24;
|
||||
dx = 'i' | 'n' << 8 | 'e' << 16 | 'C' << 24;
|
||||
cx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24;
|
||||
break;
|
||||
case 1:
|
||||
cx |= 1 << 0; // sse3
|
||||
|
|
|
@ -89,7 +89,7 @@ static char *DisError(struct Dis *d, char *p) {
|
|||
p = HighStart(p, g_high.comment);
|
||||
*p++ = '#';
|
||||
*p++ = ' ';
|
||||
p = stpcpy(p, indexdoublenulstring(kXedErrorNames, d->xedd->op.error));
|
||||
p = stpcpy(p, IndexDoubleNulString(kXedErrorNames, d->xedd->op.error));
|
||||
p = HighEnd(p);
|
||||
*p = '\0';
|
||||
return p;
|
||||
|
|
|
@ -30,10 +30,10 @@ struct Dis {
|
|||
size_t i, n;
|
||||
struct DisSym {
|
||||
int64_t addr;
|
||||
int rank;
|
||||
int unique;
|
||||
int size;
|
||||
int name;
|
||||
char rank;
|
||||
bool iscode;
|
||||
bool isabs;
|
||||
} * p;
|
||||
|
|
|
@ -156,17 +156,12 @@ static char *DisSymImpl(struct Dis *d, char *p, int64_t x, long sym) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *DisSym(struct Dis *d, char *p, int64_t x1, int64_t x2,
|
||||
bool isrelative) {
|
||||
static char *DisSym(struct Dis *d, char *p, int64_t value, int64_t addr) {
|
||||
long sym;
|
||||
if ((sym = DisFindSym(d, x2)) != -1 && d->syms.p[sym].name &&
|
||||
(d->syms.p[sym].isabs ^ isrelative)) {
|
||||
return DisSymImpl(d, p, x2, sym);
|
||||
} else if ((sym = DisFindSym(d, x1)) != -1 && d->syms.p[sym].name &&
|
||||
(d->syms.p[sym].isabs ^ isrelative)) {
|
||||
return DisSymImpl(d, p, x1, sym);
|
||||
if ((sym = DisFindSym(d, addr)) != -1 && d->syms.p[sym].name) {
|
||||
return DisSymImpl(d, p, addr, sym);
|
||||
} else {
|
||||
return DisInt(p, x1);
|
||||
return DisInt(p, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +169,7 @@ static char *DisSymLiteral(struct Dis *d, uint32_t rde, char *p, uint64_t addr,
|
|||
uint64_t ip) {
|
||||
*p++ = '$';
|
||||
p = HighStart(p, g_high.literal);
|
||||
p = DisSym(d, p, addr, addr, false);
|
||||
p = DisSym(d, p, addr, addr);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
@ -227,7 +222,7 @@ static char *DisDisp(struct Dis *d, uint32_t rde, char *p) {
|
|||
} else {
|
||||
rela = true;
|
||||
}
|
||||
p = DisSym(d, p, disp, disp, rela);
|
||||
p = DisSym(d, p, disp, disp);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
@ -477,11 +472,11 @@ static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
|
|||
|
||||
static char *DisJvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSym(d, p, RipRelative(d, d->xedd->op.disp),
|
||||
RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs), true);
|
||||
RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs));
|
||||
}
|
||||
|
||||
static char *DisAbs(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp, false);
|
||||
return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp);
|
||||
}
|
||||
|
||||
static char *DisSw(struct Dis *d, uint32_t rde, char *p) {
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/elf/struct/sym.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
|
||||
|
@ -46,38 +46,51 @@ static int DisSymCompare(const struct DisSym *a, const struct DisSym *b) {
|
|||
}
|
||||
|
||||
static void DisLoadElfLoads(struct Dis *d, struct Elf *elf) {
|
||||
long i;
|
||||
long i, j, n;
|
||||
int64_t addr;
|
||||
uint64_t size;
|
||||
Elf64_Phdr *phdr;
|
||||
struct DisLoad l;
|
||||
d->loads.i = 0;
|
||||
for (i = 0; i < elf->ehdr->e_phnum; ++i) {
|
||||
j = 0;
|
||||
n = elf->ehdr->e_phnum;
|
||||
if (d->loads.n < n) {
|
||||
d->loads.n = n;
|
||||
d->loads.p = realloc(d->loads.p, d->loads.n * sizeof(*d->loads.p));
|
||||
CHECK_NOTNULL(d->loads.p);
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
phdr = getelfsegmentheaderaddress(elf->ehdr, elf->size, i);
|
||||
if (phdr->p_type != PT_LOAD) continue;
|
||||
l.addr = phdr->p_vaddr;
|
||||
l.size = phdr->p_memsz;
|
||||
l.istext = (phdr->p_flags & PF_X) == PF_X;
|
||||
APPEND(&d->loads.p, &d->loads.i, &d->loads.n, &l);
|
||||
d->loads.p[j].addr = phdr->p_vaddr;
|
||||
d->loads.p[j].size = phdr->p_memsz;
|
||||
d->loads.p[j].istext = (phdr->p_flags & PF_X) == PF_X;
|
||||
++j;
|
||||
}
|
||||
d->loads.i = j;
|
||||
}
|
||||
|
||||
static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
|
||||
size_t i, n;
|
||||
size_t i, j, n;
|
||||
int64_t stablen;
|
||||
struct DisSym t;
|
||||
const Elf64_Sym *st, *sym;
|
||||
bool isabs, iscode, isweak, islocal, ishidden, isprotected, isfunc, isobject;
|
||||
d->syms.i = 0;
|
||||
j = 0;
|
||||
if ((d->syms.stab = getelfstringtable(elf->ehdr, elf->size)) &&
|
||||
(st = getelfsymboltable(elf->ehdr, elf->size, &n))) {
|
||||
stablen = (intptr_t)elf->ehdr + elf->size - (intptr_t)d->syms.stab;
|
||||
if (d->syms.n < n) {
|
||||
d->syms.n = n;
|
||||
d->syms.p = realloc(d->syms.p, d->syms.n * sizeof(*d->syms.p));
|
||||
CHECK_NOTNULL(d->syms.p);
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!st[i].st_name) continue;
|
||||
if (!(0 <= st[i].st_name && st[i].st_name < stablen)) continue;
|
||||
if (ELF64_ST_TYPE(st[i].st_info) == STT_SECTION) continue;
|
||||
if (ELF64_ST_TYPE(st[i].st_info) == STT_FILE) continue;
|
||||
if (startswith(d->syms.stab + st[i].st_name, "v_")) continue;
|
||||
if (ELF64_ST_TYPE(st[i].st_info) == STT_SECTION ||
|
||||
ELF64_ST_TYPE(st[i].st_info) == STT_FILE || !st[i].st_name ||
|
||||
startswith(d->syms.stab + st[i].st_name, "v_") ||
|
||||
!(0 <= st[i].st_name && st[i].st_name < stablen) || !st[i].st_value ||
|
||||
!(-0x800000000000 <= (int64_t)st[i].st_value &&
|
||||
(int64_t)st[i].st_value < 0x800000000000)) {
|
||||
continue;
|
||||
}
|
||||
isabs = st[i].st_shndx == SHN_ABS;
|
||||
isweak = ELF64_ST_BIND(st[i].st_info) == STB_WEAK;
|
||||
islocal = ELF64_ST_BIND(st[i].st_info) == STB_LOCAL;
|
||||
|
@ -85,19 +98,51 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
|
|||
isprotected = st[i].st_other == STV_PROTECTED;
|
||||
isfunc = ELF64_ST_TYPE(st[i].st_info) == STT_FUNC;
|
||||
isobject = ELF64_ST_TYPE(st[i].st_info) == STT_OBJECT;
|
||||
t.unique = i;
|
||||
t.size = st[i].st_size;
|
||||
t.name = st[i].st_name;
|
||||
t.addr = st[i].st_value;
|
||||
t.rank = -islocal + -isweak + -isabs + isprotected + isobject + isfunc;
|
||||
t.iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc;
|
||||
t.isabs = isabs;
|
||||
APPEND(&d->syms.p, &d->syms.i, &d->syms.n, &t);
|
||||
d->syms.p[j].unique = i;
|
||||
d->syms.p[j].size = st[i].st_size;
|
||||
d->syms.p[j].name = st[i].st_name;
|
||||
d->syms.p[j].addr = st[i].st_value;
|
||||
d->syms.p[j].rank =
|
||||
-islocal + -isweak + -isabs + isprotected + isobject + isfunc;
|
||||
d->syms.p[j].iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc;
|
||||
d->syms.p[j].isabs = isabs;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
d->syms.i = j;
|
||||
}
|
||||
|
||||
static void DisSortSyms(struct Dis *d) {
|
||||
qsort(d->syms.p, d->syms.i, sizeof(struct DisSym), (void *)DisSymCompare);
|
||||
}
|
||||
|
||||
static void DisCanonizeSyms(struct Dis *d) {
|
||||
int64_t i, j, a;
|
||||
if (d->syms.i) {
|
||||
i = 1;
|
||||
j = 1;
|
||||
a = d->syms.p[0].addr;
|
||||
do {
|
||||
if (d->syms.p[j].addr > a) {
|
||||
a = d->syms.p[j].addr;
|
||||
if (j > i) {
|
||||
d->syms.p[i] = d->syms.p[j];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
++j;
|
||||
} while (j < d->syms.i);
|
||||
d->syms.p = realloc(d->syms.p, sizeof(*d->syms.p) * i);
|
||||
d->syms.i = i;
|
||||
d->syms.n = i;
|
||||
}
|
||||
for (i = 0; i < d->syms.i; ++i) {
|
||||
DEBUGF("%p-%p %s", d->syms.p[i].addr,
|
||||
d->syms.p[i].addr + (d->syms.p[i].size ? d->syms.p[i].size - 1 : 0),
|
||||
d->syms.stab + d->syms.p[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
bool DisIsProg(struct Dis *d, int64_t addr) {
|
||||
long i;
|
||||
if (g_disisprog_disable) return true;
|
||||
|
@ -122,36 +167,24 @@ bool DisIsText(struct Dis *d, int64_t addr) {
|
|||
}
|
||||
|
||||
long DisFindSym(struct Dis *d, int64_t addr) {
|
||||
size_t i, l, r, m, n;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
long 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) {
|
||||
r = m;
|
||||
} else {
|
||||
l = m + 1;
|
||||
}
|
||||
}
|
||||
if (r && (addr == d->syms.p[r - 1].addr ||
|
||||
(addr > d->syms.p[r - 1].addr &&
|
||||
(addr <= d->syms.p[r - 1].addr + d->syms.p[r - 1].size ||
|
||||
!d->syms.p[r - 1].size)))) {
|
||||
return r - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -170,4 +203,6 @@ void DisLoadElf(struct Dis *d, struct Elf *elf) {
|
|||
if (!elf || !elf->ehdr) return;
|
||||
DisLoadElfLoads(d, elf);
|
||||
DisLoadElfSyms(d, elf);
|
||||
DisSortSyms(d);
|
||||
DisCanonizeSyms(d);
|
||||
}
|
||||
|
|
|
@ -53,3 +53,12 @@ uint64_t ExportFlags(uint64_t flags) {
|
|||
flags |= GetLazyParityBool(flags) << FLAGS_PF;
|
||||
return flags;
|
||||
}
|
||||
|
||||
int64_t AluFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf,
|
||||
uint32_t sf) {
|
||||
*f &= ~(1u << FLAGS_CF | 1u << FLAGS_ZF | 1u << FLAGS_SF | 1u << FLAGS_OF |
|
||||
1u << FLAGS_AF | 0xFF000000u);
|
||||
*f |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF |
|
||||
af << FLAGS_AF | (x & 0xFF) << 24;
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ COSMOPOLITAN_C_START_
|
|||
bool GetParity(uint8_t);
|
||||
uint64_t ExportFlags(uint64_t);
|
||||
void ImportFlags(struct Machine *, uint64_t);
|
||||
int64_t AluFlags(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -46,9 +46,6 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
|
|||
align = MAX(phdr->p_align, PAGESIZE);
|
||||
CHECK_EQ(1, popcnt(align));
|
||||
CHECK_EQ(0, (phdr->p_vaddr - phdr->p_offset) % align);
|
||||
/*-Type-Offset---VirtAddr-----------PhysAddr-----------FileSiz--MemSiz---Flg-Align----*/
|
||||
/*-LOAD-0x000000-0x0000000000400000-0x0000000000400000-0x0008e4-0x0008e4-R-E-0x200000-*/
|
||||
/*-LOAD-0x000fe0-0x0000000000600fe0-0x0000000000600fe0-0x000030-0x000310-RW--0x200000-*/
|
||||
felf = (int64_t)(intptr_t)code;
|
||||
vstart = ROUNDDOWN(phdr->p_vaddr, align);
|
||||
vbss = ROUNDUP(phdr->p_vaddr + phdr->p_filesz, align);
|
||||
|
@ -56,10 +53,10 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
|
|||
fstart = felf + ROUNDDOWN(phdr->p_offset, align);
|
||||
fend = felf + phdr->p_offset + phdr->p_filesz;
|
||||
bsssize = vend - vbss;
|
||||
LOGF("LOADELFLOADSEGMENT"
|
||||
" VSTART %#lx VBSS %#lx VEND %#lx"
|
||||
" FSTART %#lx FEND %#lx BSSSIZE %#lx",
|
||||
vstart, vbss, vend, fstart, fend, bsssize);
|
||||
VERBOSEF("LOADELFLOADSEGMENT"
|
||||
" VSTART %#lx VBSS %#lx VEND %#lx"
|
||||
" FSTART %#lx FEND %#lx BSSSIZE %#lx",
|
||||
vstart, vbss, vend, fstart, fend, bsssize);
|
||||
m->brk = MAX(m->brk, vend);
|
||||
CHECK_GE(vend, vstart);
|
||||
CHECK_GE(fend, fstart);
|
||||
|
@ -69,9 +66,9 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
|
|||
CHECK_GE(vend - vstart, fstart - fend);
|
||||
CHECK_LE(phdr->p_filesz, phdr->p_memsz);
|
||||
CHECK_EQ(felf + phdr->p_offset - fstart, phdr->p_vaddr - vstart);
|
||||
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart));
|
||||
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart, 0x0207));
|
||||
VirtualRecv(m, vstart, (void *)fstart, fend - fstart);
|
||||
if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize));
|
||||
if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize, 0x0207));
|
||||
if (phdr->p_memsz - phdr->p_filesz > bsssize) {
|
||||
VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0,
|
||||
phdr->p_memsz - phdr->p_filesz - bsssize);
|
||||
|
@ -82,7 +79,7 @@ static void LoadElf(struct Machine *m, struct Elf *elf) {
|
|||
unsigned i;
|
||||
Elf64_Phdr *phdr;
|
||||
m->ip = elf->base = elf->ehdr->e_entry;
|
||||
LOGF("LOADELF ENTRY %p", m->ip);
|
||||
VERBOSEF("LOADELF ENTRY %p", m->ip);
|
||||
for (i = 0; i < elf->ehdr->e_phnum; ++i) {
|
||||
phdr = getelfsegmentheaderaddress(elf->ehdr, elf->size, i);
|
||||
switch (phdr->p_type) {
|
||||
|
@ -149,9 +146,9 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
|||
}
|
||||
CHECK_NE(-1, close(fd));
|
||||
ResetCpu(m);
|
||||
if (m->mode == XED_MACHINE_MODE_REAL) {
|
||||
if ((m->mode & 3) == XED_MODE_REAL) {
|
||||
elf->base = 0x7c00;
|
||||
CHECK_NE(-1, ReserveVirtual(m, 0, BIGPAGESIZE));
|
||||
CHECK_NE(-1, ReserveReal(m, BIGPAGESIZE));
|
||||
m->ip = 0x7c00;
|
||||
Write64(m->cs, 0);
|
||||
Write64(m->dx, 0);
|
||||
|
@ -168,7 +165,8 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
|||
} else {
|
||||
sp = 0x800000000000;
|
||||
Write64(m->sp, sp);
|
||||
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE));
|
||||
m->cr3 = AllocateLinearPage(m);
|
||||
CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE, 0x0207));
|
||||
LoadArgv(m, prog, args, vars);
|
||||
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
||||
elf->ehdr = (void *)elf->map;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/op101.h"
|
||||
#include "tool/build/lib/sse.h"
|
||||
#include "tool/build/lib/ssefloat.h"
|
||||
#include "tool/build/lib/ssemov.h"
|
||||
|
@ -883,9 +884,6 @@ static void OpBsubiImm(struct Machine *m, uint32_t rde) {
|
|||
Bsubi(m, rde, m->xedd->op.uimm0);
|
||||
}
|
||||
|
||||
static void OpLgdtMs(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void OpPushImm(struct Machine *m, uint32_t rde) {
|
||||
Push(m, rde, m->xedd->op.uimm0);
|
||||
}
|
||||
|
@ -1328,21 +1326,6 @@ static void Op0ff(struct Machine *m, uint32_t rde) {
|
|||
kOp0ff[ModrmReg(rde)](m, rde);
|
||||
}
|
||||
|
||||
static void Op101(struct Machine *m, uint32_t rde) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
if (ModrmReg(rde) == 0b111 && ModrmRm(rde) == 0b001) {
|
||||
OpRdtscp(m, rde);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (ModrmReg(rde) == 2) {
|
||||
OpLgdtMs(m, rde);
|
||||
return;
|
||||
}
|
||||
}
|
||||
OpUd(m, rde);
|
||||
}
|
||||
|
||||
static void OpDoubleShift(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
uint64_t x;
|
||||
|
@ -1400,6 +1383,44 @@ static void OpNop(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OpMovRqCq(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmReg(rde)) {
|
||||
case 0:
|
||||
Write64(RegRexbRm(m, rde), m->cr0);
|
||||
break;
|
||||
case 2:
|
||||
Write64(RegRexbRm(m, rde), m->cr2);
|
||||
break;
|
||||
case 3:
|
||||
Write64(RegRexbRm(m, rde), m->cr3);
|
||||
break;
|
||||
case 4:
|
||||
Write64(RegRexbRm(m, rde), m->cr4);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
static void OpMovCqRq(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmReg(rde)) {
|
||||
case 0:
|
||||
m->cr0 = Read64(RegRexbRm(m, rde));
|
||||
break;
|
||||
case 2:
|
||||
m->cr2 = Read64(RegRexbRm(m, rde));
|
||||
break;
|
||||
case 3:
|
||||
m->cr3 = Read64(RegRexbRm(m, rde));
|
||||
break;
|
||||
case 4:
|
||||
m->cr4 = Read64(RegRexbRm(m, rde));
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
static const nexgen32e_f kNexgen32e[] = {
|
||||
[0x000] = OpAlubAdd,
|
||||
[0x001] = OpAluw,
|
||||
|
@ -1689,9 +1710,9 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x11D] = OpHintNopEv,
|
||||
[0x11E] = OpUd,
|
||||
[0x11F] = OpNopEv,
|
||||
[0x120] = OpUd,
|
||||
[0x120] = OpMovRqCq,
|
||||
[0x121] = OpUd,
|
||||
[0x122] = OpUd,
|
||||
[0x122] = OpMovCqRq,
|
||||
[0x123] = OpUd,
|
||||
[0x124] = OpUd,
|
||||
[0x125] = OpUd,
|
||||
|
|
|
@ -131,6 +131,9 @@ struct Machine {
|
|||
};
|
||||
};
|
||||
} sse;
|
||||
uint64_t cr0;
|
||||
uint64_t cr2;
|
||||
uint64_t cr4;
|
||||
struct MachineRealFree {
|
||||
uint64_t i;
|
||||
uint64_t n;
|
||||
|
@ -140,6 +143,15 @@ struct Machine {
|
|||
uint32_t i;
|
||||
void *p[6];
|
||||
} freelist;
|
||||
struct MachineMemstat {
|
||||
int freed;
|
||||
int resizes;
|
||||
int reserved;
|
||||
int committed;
|
||||
int allocated;
|
||||
int reclaimed;
|
||||
int pagetables;
|
||||
} memstat;
|
||||
int64_t brk;
|
||||
int64_t bofram[2];
|
||||
jmp_buf onhalt;
|
||||
|
@ -157,7 +169,9 @@ void ResetTlb(struct Machine *);
|
|||
void LoadInstruction(struct Machine *);
|
||||
void ExecuteInstruction(struct Machine *);
|
||||
long AllocateLinearPage(struct Machine *);
|
||||
int ReserveVirtual(struct Machine *, int64_t, size_t);
|
||||
long AllocateLinearPageRaw(struct Machine *);
|
||||
int ReserveReal(struct Machine *, size_t);
|
||||
int ReserveVirtual(struct Machine *, int64_t, size_t, uint64_t);
|
||||
char *FormatPml4t(struct Machine *) nodiscard;
|
||||
int64_t FindVirtual(struct Machine *, int64_t, size_t);
|
||||
int FreeVirtual(struct Machine *, int64_t, size_t);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -44,41 +45,58 @@ void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
long HandlePageFault(struct Machine *m, uint64_t entry, uint64_t table,
|
||||
unsigned index) {
|
||||
long page;
|
||||
if ((page = AllocateLinearPage(m)) != -1) {
|
||||
--m->memstat.reserved;
|
||||
*(uint64_t *)(m->real.p + table + index * 8) =
|
||||
page | entry & ~0x7ffffffffe00;
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
void *FindReal(struct Machine *m, int64_t virt) {
|
||||
uint8_t *host;
|
||||
uint64_t real, pte, *pt;
|
||||
unsigned skew, level, i;
|
||||
if (!(-0x800000000000 <= virt && virt < 0x800000000000)) {
|
||||
long page;
|
||||
uint64_t table, entry;
|
||||
unsigned skew, level, index, i;
|
||||
if ((m->mode & 3) != XED_MODE_REAL) {
|
||||
if (-0x800000000000 <= virt && virt < 0x800000000000) {
|
||||
skew = virt & 0xfff;
|
||||
virt &= -0x1000;
|
||||
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
|
||||
if (m->tlb[i].virt == virt && m->tlb[i].host) {
|
||||
return m->tlb[i].host + skew;
|
||||
}
|
||||
}
|
||||
level = 39;
|
||||
entry = m->cr3;
|
||||
do {
|
||||
table = entry & 0x7ffffffff000;
|
||||
CHECK_LT(table, m->real.n);
|
||||
index = (virt >> level) & 511;
|
||||
entry = *(uint64_t *)(m->real.p + table + index * 8);
|
||||
if (!(entry & 1)) return NULL;
|
||||
} while ((level -= 9) >= 12);
|
||||
if (!(entry & 0x0e00)) {
|
||||
page = entry & 0x7ffffffff000;
|
||||
CHECK_LT(page, m->real.n);
|
||||
} else if ((page = HandlePageFault(m, entry, table, index)) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
|
||||
m->tlb[m->tlbindex] = m->tlb[0];
|
||||
m->tlb[0].virt = virt;
|
||||
m->tlb[0].host = m->real.p + page;
|
||||
return m->real.p + page + skew;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else if (0 <= virt && virt + 0xfff < m->real.n) {
|
||||
return m->real.p + virt;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
skew = virt & 0xfff;
|
||||
virt &= -0x1000;
|
||||
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
|
||||
if (m->tlb[i].virt == virt && m->tlb[i].host) {
|
||||
return m->tlb[i].host + skew;
|
||||
}
|
||||
}
|
||||
level = 39;
|
||||
real = m->cr3;
|
||||
for (;;) {
|
||||
if (real + 0x1000 > m->real.n) {
|
||||
return NULL;
|
||||
}
|
||||
host = m->real.p + real;
|
||||
if (level < 12) break;
|
||||
pt = (uint64_t *)host;
|
||||
pte = pt[(virt >> level) & 511];
|
||||
if (!(pte & 1)) {
|
||||
return NULL;
|
||||
}
|
||||
real = pte & 0x00007ffffffff000;
|
||||
level -= 9;
|
||||
}
|
||||
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
|
||||
m->tlb[m->tlbindex] = m->tlb[0];
|
||||
m->tlb[0].host = host;
|
||||
m->tlb[0].virt = virt;
|
||||
return host + skew;
|
||||
}
|
||||
|
||||
void *ResolveAddress(struct Machine *m, int64_t v) {
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
struct Machine *NewMachine(void) {
|
||||
struct Machine *m;
|
||||
m = xmemalignzero(alignof(struct Machine), sizeof(struct Machine));
|
||||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
ResetCpu(m);
|
||||
ResetMem(m);
|
||||
return m;
|
||||
|
@ -60,11 +59,20 @@ void FreeMachine(struct Machine *m) {
|
|||
void ResetMem(struct Machine *m) {
|
||||
FreeMachineRealFree(m);
|
||||
ResetTlb(m);
|
||||
memset(&m->memstat, 0, sizeof(m->memstat));
|
||||
m->real.i = 0;
|
||||
m->cr3 = AllocateLinearPage(m);
|
||||
m->cr3 = 0;
|
||||
}
|
||||
|
||||
long AllocateLinearPage(struct Machine *m) {
|
||||
long page;
|
||||
if ((page = AllocateLinearPageRaw(m)) != -1) {
|
||||
memset(m->real.p + page, 0, 0x1000);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
long AllocateLinearPageRaw(struct Machine *m) {
|
||||
uint8_t *p;
|
||||
size_t i, n;
|
||||
struct MachineRealFree *rf;
|
||||
|
@ -79,6 +87,8 @@ long AllocateLinearPage(struct Machine *m) {
|
|||
m->realfree = rf->next;
|
||||
free(rf);
|
||||
}
|
||||
--m->memstat.freed;
|
||||
++m->memstat.reclaimed;
|
||||
} else {
|
||||
i = m->real.i;
|
||||
n = m->real.n;
|
||||
|
@ -94,6 +104,7 @@ long AllocateLinearPage(struct Machine *m) {
|
|||
m->real.p = p;
|
||||
m->real.n = n;
|
||||
ResetTlb(m);
|
||||
++m->memstat.resizes;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
@ -102,8 +113,9 @@ long AllocateLinearPage(struct Machine *m) {
|
|||
DCHECK_EQ(0, n & 0xfff);
|
||||
DCHECK_LE(i + 0x1000, n);
|
||||
m->real.i += 0x1000;
|
||||
++m->memstat.allocated;
|
||||
}
|
||||
memset(m->real.p + i, 0, 0x1000); /* TODO: lazy page clearing */
|
||||
++m->memstat.committed;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -117,24 +129,51 @@ static void MachineWrite64(struct Machine *m, unsigned long i, uint64_t x) {
|
|||
Write64(m->real.p + i, x);
|
||||
}
|
||||
|
||||
int ReserveVirtual(struct Machine *m, int64_t virt, size_t size) {
|
||||
int64_t level, pt, ti, mi, end;
|
||||
for (end = virt + size; virt < end; virt += 0x1000) {
|
||||
for (pt = m->cr3, level = 39; level >= 12; level -= 9) {
|
||||
pt = pt & 0x00007ffffffff000;
|
||||
ti = (virt >> level) & 511;
|
||||
DEBUGF("reserve %p level %d table %p index %ld", virt, level, pt, ti);
|
||||
mi = pt + ti * 8;
|
||||
pt = MachineRead64(m, mi);
|
||||
if (!(pt & 1)) {
|
||||
if ((pt = AllocateLinearPage(m)) == -1) return -1;
|
||||
MachineWrite64(m, mi, pt | 7);
|
||||
}
|
||||
int ReserveReal(struct Machine *m, size_t n) {
|
||||
uint8_t *p;
|
||||
DCHECK_EQ(0, n & 0xfff);
|
||||
if (m->real.n < n) {
|
||||
if ((p = realloc(m->real.p, n))) {
|
||||
m->real.p = p;
|
||||
m->real.n = n;
|
||||
ResetTlb(m);
|
||||
++m->memstat.resizes;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ReserveVirtual(struct Machine *m, int64_t virt, size_t size, uint64_t key) {
|
||||
int64_t ti, mi, pt, end, level;
|
||||
for (end = virt + size;;) {
|
||||
for (pt = m->cr3, level = 39; level >= 12; level -= 9) {
|
||||
pt = pt & 0x7ffffffff000;
|
||||
ti = (virt >> level) & 511;
|
||||
mi = (pt & 0x7ffffffff000) + ti * 8;
|
||||
pt = MachineRead64(m, mi);
|
||||
if (level > 12) {
|
||||
if (!(pt & 1)) {
|
||||
if ((pt = AllocateLinearPage(m)) == -1) return -1;
|
||||
MachineWrite64(m, mi, pt | 7);
|
||||
++m->memstat.pagetables;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (;;) {
|
||||
if (!(pt & 1)) {
|
||||
MachineWrite64(m, mi, key);
|
||||
++m->memstat.reserved;
|
||||
}
|
||||
if ((virt += 0x1000) >= end) return 0;
|
||||
if (++ti == 512) break;
|
||||
pt = MachineRead64(m, (mi += 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
|
||||
uint64_t i, pt, got;
|
||||
got = 0;
|
||||
|
@ -154,30 +193,39 @@ int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
|
|||
return virt;
|
||||
}
|
||||
|
||||
int FreeVirtual(struct Machine *m, int64_t base, size_t size) {
|
||||
static void AppendRealFree(struct Machine *m, uint64_t real) {
|
||||
struct MachineRealFree *rf;
|
||||
uint64_t i, mi, pt, la, end, virt;
|
||||
for (virt = base, end = virt + size; virt < end;) {
|
||||
if (m->realfree && real == m->realfree->i + m->realfree->n) {
|
||||
m->realfree->n += 0x1000;
|
||||
} else if ((rf = malloc(sizeof(struct MachineRealFree)))) {
|
||||
rf->i = real;
|
||||
rf->n = 0x1000;
|
||||
rf->next = m->realfree;
|
||||
m->realfree = rf;
|
||||
}
|
||||
}
|
||||
|
||||
int FreeVirtual(struct Machine *m, int64_t base, size_t size) {
|
||||
uint64_t i, mi, pt, end, virt;
|
||||
for (virt = base, end = virt + size; virt < end; virt += 1ull << i) {
|
||||
for (pt = m->cr3, i = 39;; i -= 9) {
|
||||
mi = (pt & 0x7ffffffff000) + ((virt >> i) & 511) * 8;
|
||||
pt = MachineRead64(m, mi);
|
||||
if (!(pt & 1)) {
|
||||
break;
|
||||
} else if (i == 12) {
|
||||
MachineWrite64(m, mi, 0);
|
||||
la = pt & 0x7ffffffff000;
|
||||
if (m->realfree && la == m->realfree->i + m->realfree->n) {
|
||||
m->realfree->n += 0x1000;
|
||||
} else if ((rf = malloc(sizeof(struct MachineRealFree)))) {
|
||||
rf->i = la;
|
||||
rf->n = 0x1000;
|
||||
rf->next = m->realfree;
|
||||
m->realfree = rf;
|
||||
++m->memstat.freed;
|
||||
if (pt & 0x0e00) {
|
||||
--m->memstat.reserved;
|
||||
} else {
|
||||
--m->memstat.committed;
|
||||
AppendRealFree(m, pt & 0x7ffffffff000);
|
||||
}
|
||||
MachineWrite64(m, mi, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
virt += 1ull << i;
|
||||
}
|
||||
ResetTlb(m);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,10 @@ uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *m, uint32_t rde,
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite2(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 2);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 4);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ extern const uint8_t kByteReg[32];
|
|||
|
||||
int64_t ComputeAddress(const struct Machine *, uint32_t);
|
||||
struct AddrSeg LoadEffectiveAddress(const struct Machine *, uint32_t);
|
||||
|
||||
void *ComputeReserveAddressRead(struct Machine *, uint32_t, size_t);
|
||||
void *ComputeReserveAddressRead1(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressRead4(struct Machine *, uint32_t);
|
||||
|
@ -68,7 +67,6 @@ void *ComputeReserveAddressWrite(struct Machine *, uint32_t, size_t);
|
|||
void *ComputeReserveAddressWrite1(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressWrite4(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressWrite8(struct Machine *, uint32_t);
|
||||
|
||||
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *, uint32_t, size_t);
|
||||
|
@ -82,6 +80,7 @@ uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *, uint32_t);
|
|||
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite2(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *, uint32_t);
|
||||
|
|
160
tool/build/lib/op101.c
Normal file
160
tool/build/lib/op101.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*-*- 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/endian.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/op101.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
#include "tool/build/lib/time.h"
|
||||
|
||||
static void SgdtMs(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void LgdtMs(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void SidtMs(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void LidtMs(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Monitor(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Mwait(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Swapgs(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Vmcall(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Vmlaunch(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Vmresume(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Vmxoff(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void InvlpgM(struct Machine *m, uint32_t rde) {
|
||||
ResetTlb(m);
|
||||
}
|
||||
|
||||
static void Smsw(struct Machine *m, uint32_t rde, bool ismem) {
|
||||
if (ismem) {
|
||||
Write16(GetModrmRegisterWordPointerWrite2(m, rde), m->cr0);
|
||||
} else if (Rexw(rde)) {
|
||||
Write64(RegRexrReg(m, rde), m->cr0);
|
||||
} else if (!Osz(rde)) {
|
||||
Write64(RegRexrReg(m, rde), m->cr0 & 0xffffffff);
|
||||
} else {
|
||||
Write16(RegRexrReg(m, rde), m->cr0);
|
||||
}
|
||||
}
|
||||
|
||||
static void Lmsw(struct Machine *m, uint32_t rde) {
|
||||
m->cr0 = Read16(GetModrmRegisterWordPointerRead2(m, rde));
|
||||
}
|
||||
|
||||
void Op101(struct Machine *m, uint32_t rde) {
|
||||
bool ismem;
|
||||
ismem = !IsModrmRegister(rde);
|
||||
switch (ModrmReg(rde)) {
|
||||
case 0:
|
||||
if (ismem) {
|
||||
SgdtMs(m, rde);
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
case 1:
|
||||
Vmcall(m, rde);
|
||||
break;
|
||||
case 2:
|
||||
Vmlaunch(m, rde);
|
||||
break;
|
||||
case 3:
|
||||
Vmresume(m, rde);
|
||||
break;
|
||||
case 4:
|
||||
Vmxoff(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (ismem) {
|
||||
SidtMs(m, rde);
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
case 0:
|
||||
Monitor(m, rde);
|
||||
break;
|
||||
case 1:
|
||||
Mwait(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (ismem) {
|
||||
LgdtMs(m, rde);
|
||||
} else {
|
||||
OpUd(m, rde);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (ismem) {
|
||||
LidtMs(m, rde);
|
||||
} else {
|
||||
OpUd(m, rde);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
Smsw(m, rde, ismem);
|
||||
break;
|
||||
case 6:
|
||||
Lmsw(m, rde);
|
||||
break;
|
||||
case 7:
|
||||
if (ismem) {
|
||||
InvlpgM(m, rde);
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
case 0:
|
||||
Swapgs(m, rde);
|
||||
break;
|
||||
case 1:
|
||||
OpRdtscp(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
11
tool/build/lib/op101.h
Normal file
11
tool/build/lib/op101.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void Op101(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_ */
|
|
@ -5,10 +5,12 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Panel {
|
||||
int i;
|
||||
int top, bottom;
|
||||
int left, right;
|
||||
int top;
|
||||
int bottom;
|
||||
int left;
|
||||
int right;
|
||||
struct Buffer *lines;
|
||||
size_t n;
|
||||
};
|
||||
|
||||
ssize_t PrintPanels(int, long, struct Panel *, long, long);
|
||||
|
|
|
@ -70,6 +70,7 @@ char *FormatPml4t(struct Machine *m) {
|
|||
unsigned short i, a[4];
|
||||
struct Pml4tFormater pp = {0};
|
||||
unsigned short range[][2] = {{256, 512}, {0, 256}};
|
||||
if ((m->mode & 3) != XED_MODE_LONG) return strdup("");
|
||||
pd[0] = GetPt(m, m->cr3);
|
||||
for (i = 0; i < ARRAYLEN(range); ++i) {
|
||||
a[0] = range[i][0];
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,36 +2,36 @@
|
|||
#define COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_
|
||||
#include "tool/build/lib/buffer.h"
|
||||
|
||||
#define kMachinePtyFg 0x0001
|
||||
#define kMachinePtyBg 0x0002
|
||||
#define kMachinePtyBold 0x0004
|
||||
#define kMachinePtyFlip 0x0008
|
||||
#define kMachinePtyFaint 0x0010
|
||||
#define kMachinePtyUnder 0x0020
|
||||
#define kMachinePtyDunder 0x0040
|
||||
#define kMachinePtyTrue 0x0080
|
||||
#define kMachinePtyBlink 0x0100
|
||||
#define kMachinePtyItalic 0x0200
|
||||
#define kMachinePtyFraktur 0x0400
|
||||
#define kMachinePtyStrike 0x0800
|
||||
#define kMachinePtyConceal 0x1000
|
||||
#define kPtyFg 0x0001
|
||||
#define kPtyBg 0x0002
|
||||
#define kPtyBold 0x0004
|
||||
#define kPtyFlip 0x0008
|
||||
#define kPtyFaint 0x0010
|
||||
#define kPtyUnder 0x0020
|
||||
#define kPtyDunder 0x0040
|
||||
#define kPtyTrue 0x0080
|
||||
#define kPtyBlink 0x0100
|
||||
#define kPtyItalic 0x0200
|
||||
#define kPtyFraktur 0x0400
|
||||
#define kPtyStrike 0x0800
|
||||
#define kPtyConceal 0x1000
|
||||
|
||||
#define kMachinePtyBell 0x001
|
||||
#define kMachinePtyRedzone 0x002
|
||||
#define kMachinePtyNocursor 0x004
|
||||
#define kMachinePtyBlinkcursor 0x008
|
||||
#define kMachinePtyNocanon 0x010
|
||||
#define kMachinePtyNoecho 0x020
|
||||
#define kMachinePtyNoopost 0x040
|
||||
#define kMachinePtyLed1 0x080
|
||||
#define kMachinePtyLed2 0x100
|
||||
#define kMachinePtyLed3 0x200
|
||||
#define kMachinePtyLed4 0x400
|
||||
#define kPtyBell 0x001
|
||||
#define kPtyRedzone 0x002
|
||||
#define kPtyNocursor 0x004
|
||||
#define kPtyBlinkcursor 0x008
|
||||
#define kPtyNocanon 0x010
|
||||
#define kPtyNoecho 0x020
|
||||
#define kPtyNoopost 0x040
|
||||
#define kPtyLed1 0x080
|
||||
#define kPtyLed2 0x100
|
||||
#define kPtyLed3 0x200
|
||||
#define kPtyLed4 0x400
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct MachinePty {
|
||||
struct Pty {
|
||||
int y;
|
||||
int x;
|
||||
int yn;
|
||||
|
@ -48,34 +48,34 @@ struct MachinePty {
|
|||
uint32_t *fgs;
|
||||
uint32_t *bgs;
|
||||
wchar_t *xlat;
|
||||
enum MachinePtyState {
|
||||
kMachinePtyAscii,
|
||||
kMachinePtyUtf8,
|
||||
kMachinePtyEsc,
|
||||
kMachinePtyCsi,
|
||||
enum PtyState {
|
||||
kPtyAscii,
|
||||
kPtyUtf8,
|
||||
kPtyEsc,
|
||||
kPtyCsi,
|
||||
} state;
|
||||
struct MachinePtyEsc {
|
||||
struct PtyEsc {
|
||||
unsigned i;
|
||||
char s[64];
|
||||
} esc;
|
||||
struct MachinePtyInput {
|
||||
struct PtyInput {
|
||||
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);
|
||||
void MachinePtyFullReset(struct MachinePty *);
|
||||
void MachinePtyMemmove(struct MachinePty *, long, long, long);
|
||||
void MachinePtyErase(struct MachinePty *, long, long);
|
||||
void MachinePtySetY(struct MachinePty *, int);
|
||||
void MachinePtySetX(struct MachinePty *, int);
|
||||
void FreePty(struct Pty *);
|
||||
struct Pty *NewPty(void) nodiscard;
|
||||
void PtyResize(struct Pty *, int, int);
|
||||
ssize_t PtyRead(struct Pty *, void *, size_t);
|
||||
ssize_t PtyWrite(struct Pty *, const void *, size_t);
|
||||
ssize_t PtyWriteInput(struct Pty *, const void *, size_t);
|
||||
int PtyAppendLine(struct Pty *, struct Buffer *, unsigned);
|
||||
void PtyFullReset(struct Pty *);
|
||||
void PtyMemmove(struct Pty *, long, long, long);
|
||||
void PtyErase(struct Pty *, long, long);
|
||||
void PtySetY(struct Pty *, int);
|
||||
void PtySetX(struct Pty *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/address.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
|
@ -496,23 +497,9 @@ void OpMov0fD6(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
static uint8_t pmovmskb(uint64_t x) {
|
||||
return (x & 0x0000000000000080) >> 007 | (x & 0x0000000000008000) >> 016 |
|
||||
(x & 0x0000000000800000) >> 025 | (x & 0x0000000080000000) >> 034 |
|
||||
(x & 0x0000008000000000) >> 043 | (x & 0x0000800000000000) >> 052 |
|
||||
(x & 0x0080000000000000) >> 061 | (x & 0x8000000000000000) >> 070;
|
||||
}
|
||||
|
||||
void OpPmovmskbGdqpNqUdq(struct Machine *m, uint32_t rde) {
|
||||
uint64_t bitmask;
|
||||
if (Osz(rde)) {
|
||||
bitmask = pmovmskb(Read64(XmmRexbRm(m, rde) + 8)) << 8 |
|
||||
pmovmskb(Read64(XmmRexbRm(m, rde)));
|
||||
} else {
|
||||
bitmask = pmovmskb(Read64(MmRm(m, rde) + 8)) << 8 |
|
||||
pmovmskb(Read64(MmRm(m, rde)));
|
||||
}
|
||||
Write64(RegRexrReg(m, rde), bitmask);
|
||||
Write64(RegRexrReg(m, rde),
|
||||
pmovmskb(XmmRexbRm(m, rde)) & (Osz(rde) ? 0xffff : 0xff));
|
||||
}
|
||||
|
||||
void OpMaskMovDiXmmRegXmmRm(struct Machine *m, uint32_t rde) {
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/lib/stats.h"
|
||||
|
||||
unsigned long ops;
|
||||
unsigned long taken;
|
||||
unsigned long ntaken;
|
||||
unsigned long opcount;
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern unsigned long ops;
|
||||
extern unsigned long taken;
|
||||
extern unsigned long ntaken;
|
||||
extern unsigned long opcount;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
|
@ -321,11 +322,22 @@ static int XlatMsyncFlags(int x) {
|
|||
return res;
|
||||
}
|
||||
|
||||
static unsigned XlatOpenMode(unsigned flags) {
|
||||
switch (flags & 3) {
|
||||
case 0:
|
||||
return O_RDONLY;
|
||||
case 1:
|
||||
return O_WRONLY;
|
||||
case 2:
|
||||
return O_RDWR;
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned XlatOpenFlags(unsigned flags) {
|
||||
unsigned res = 0;
|
||||
if ((flags & 3) == 0) res = O_RDONLY;
|
||||
if ((flags & 3) == 1) res = O_WRONLY;
|
||||
if ((flags & 3) == 3) res = O_RDWR;
|
||||
res = XlatOpenMode(flags);
|
||||
if (flags & 0x80000) res |= O_CLOEXEC;
|
||||
if (flags & 0x400) res |= O_APPEND;
|
||||
if (flags & 0x40) res |= O_CREAT;
|
||||
|
@ -355,6 +367,7 @@ static int XlatFcntlArg(int x) {
|
|||
switch (x) {
|
||||
XLAT(0, 0);
|
||||
XLAT(1, FD_CLOEXEC);
|
||||
XLAT(0x0800, O_NONBLOCK);
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
|
@ -401,6 +414,14 @@ static int XlatRusage(int x) {
|
|||
}
|
||||
}
|
||||
|
||||
static const char *GetSimulated(void) {
|
||||
if (IsGenuineCosmo()) {
|
||||
return " SIMULATED";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static void VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
|
||||
uint64_t n) {
|
||||
VirtualSend(m, dst, addr, n);
|
||||
|
@ -508,7 +529,7 @@ static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
|
|||
static int64_t OpBrk(struct Machine *m, int64_t addr) {
|
||||
addr = ROUNDUP(addr, PAGESIZE);
|
||||
if (addr > m->brk) {
|
||||
if (ReserveVirtual(m, m->brk, addr - m->brk) != -1) {
|
||||
if (ReserveVirtual(m, m->brk, addr - m->brk, 0x0207) != -1) {
|
||||
m->brk = addr;
|
||||
}
|
||||
} else if (addr < m->brk) {
|
||||
|
@ -519,34 +540,47 @@ static int64_t OpBrk(struct Machine *m, int64_t addr) {
|
|||
return m->brk;
|
||||
}
|
||||
|
||||
static int OpMunmap(struct Machine *m, int64_t virt, uint64_t size) {
|
||||
VERBOSEF("MUNMAP%s %p %,ld", GetSimulated(), virt, size);
|
||||
return FreeVirtual(m, virt, size);
|
||||
}
|
||||
|
||||
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
|
||||
int flags, int fd, int64_t offset) {
|
||||
void *tmp;
|
||||
LOGF("MMAP%s %p %,ld %#x %#x %d %#lx", IsGenuineCosmo() ? " SIMULATED" : "",
|
||||
virt, size, prot, flags, fd, offset);
|
||||
flags = XlatMapFlags(flags);
|
||||
if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
if (!virt) {
|
||||
if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1;
|
||||
m->brk = virt + size;
|
||||
} else {
|
||||
if ((virt = FindVirtual(m, virt, size)) == -1) return -1;
|
||||
uint64_t key;
|
||||
VERBOSEF("MMAP%s %p %,ld %#x %#x %d %#lx", GetSimulated(), virt, size, prot,
|
||||
flags, fd, offset);
|
||||
if (prot & PROT_READ) {
|
||||
key = 0x0205;
|
||||
if (prot & PROT_WRITE) key |= 2;
|
||||
if (!(prot & PROT_EXEC)) key |= 0x8000000000000000;
|
||||
flags = XlatMapFlags(flags);
|
||||
if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
if (!virt) {
|
||||
if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1;
|
||||
m->brk = virt + size;
|
||||
} else {
|
||||
if ((virt = FindVirtual(m, virt, size)) == -1) return -1;
|
||||
}
|
||||
}
|
||||
if (ReserveVirtual(m, virt, size, key) != -1) {
|
||||
if (fd != -1 && !(flags & MAP_ANONYMOUS)) {
|
||||
/* TODO: lazy file mappings */
|
||||
CHECK_NOTNULL((tmp = malloc(size)));
|
||||
CHECK_EQ(size, pread(fd, tmp, size, offset));
|
||||
VirtualRecvWrite(m, virt, tmp, size);
|
||||
free(tmp);
|
||||
}
|
||||
} else {
|
||||
FreeVirtual(m, virt, size);
|
||||
return -1;
|
||||
}
|
||||
return virt;
|
||||
} else {
|
||||
return FreeVirtual(m, virt, size);
|
||||
}
|
||||
if (ReserveVirtual(m, virt, size) == -1) return -1;
|
||||
if (fd != -1 && !(flags & MAP_ANONYMOUS)) {
|
||||
/* TODO: lazy page loading */
|
||||
CHECK_NOTNULL((tmp = malloc(size)));
|
||||
CHECK_EQ(size, pread(fd, tmp, size, offset));
|
||||
VirtualRecvWrite(m, virt, tmp, size);
|
||||
free(tmp);
|
||||
}
|
||||
return virt;
|
||||
}
|
||||
|
||||
static int OpMunmap(struct Machine *m, int64_t addr, uint64_t size) {
|
||||
return FreeVirtual(m, addr, size);
|
||||
}
|
||||
|
||||
static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
|
||||
|
@ -574,18 +608,23 @@ static int OpClose(struct Machine *m, int fd) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags,
|
||||
static int OpOpenat(struct Machine *m, int dirfd, int64_t pathaddr, int flags,
|
||||
int mode) {
|
||||
int fd, i;
|
||||
const char *path;
|
||||
flags = XlatOpenFlags(flags);
|
||||
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
|
||||
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
|
||||
if ((fd = openat(dirfd, LoadStr(m, path), flags, mode)) != -1) {
|
||||
path = LoadStr(m, pathaddr);
|
||||
if ((fd = openat(dirfd, path, flags, mode)) != -1) {
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
m->fds.p[i].fd = fd;
|
||||
VERBOSEF("openat(%#x, %`'s, %#x, %#x) → %d [%d]", dirfd, path, flags, mode,
|
||||
i, fd);
|
||||
fd = i;
|
||||
} else {
|
||||
MachineFdRemove(&m->fds, i);
|
||||
VERBOSEF("openat(%#x, %`'s, %#x, %#x) failed", dirfd, path, flags, mode);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
@ -768,9 +807,13 @@ static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
|
|||
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
|
||||
if ((rc = m->fds.p[fd].cb->writev(m->fds.p[fd].fd, iv.p, iv.i)) != -1) {
|
||||
SetReadAddr(m, addr, rc);
|
||||
} else {
|
||||
VERBOSEF("write(%d [%d], %p, %zu) failed: %s", fd, m->fds.p[fd].fd,
|
||||
addr, size, strerror(errno));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VERBOSEF("write(%d, %p, %zu) bad fd", fd, addr, size);
|
||||
rc = ebadf();
|
||||
}
|
||||
FreeIovs(&iv);
|
||||
|
@ -1363,7 +1406,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
|
|||
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
|
||||
CASE(0xE7, HaltMachine(m, di | 0x100));
|
||||
default:
|
||||
LOGF("missing syscall 0x%03x", ax);
|
||||
VERBOSEF("missing syscall 0x%03x", ax);
|
||||
ax = enosys();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/vendor.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/address.h"
|
||||
|
@ -34,7 +35,7 @@ static bool IsHaltingInitialized(struct Machine *m) {
|
|||
|
||||
void HaltMachine(struct Machine *m, int code) {
|
||||
CHECK(IsHaltingInitialized(m));
|
||||
longjmp(m->onhalt, code);
|
||||
gclongjmp(m->onhalt, code);
|
||||
}
|
||||
|
||||
void ThrowDivideError(struct Machine *m) {
|
||||
|
|
|
@ -17,19 +17,22 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/loader.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/pty.h"
|
||||
#include "tool/build/lib/syscall.h"
|
||||
|
||||
static void AddHostFd(struct Machine *m, int fd) {
|
||||
int i = m->fds.i++;
|
||||
CHECK_NE(-1, (m->fds.p[i].fd = dup(fd)));
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int rc;
|
||||
struct Elf elf;
|
||||
|
@ -42,15 +45,10 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
m = NewMachine();
|
||||
LoadProgram(m, argv[1], argv + 2, environ, &elf);
|
||||
m->fds.i = 3;
|
||||
m->fds.n = 8;
|
||||
m->fds.p = xcalloc(m->fds.n, sizeof(struct MachineFd));
|
||||
m->fds.p[0].fd = STDIN_FILENO;
|
||||
m->fds.p[0].cb = &kMachineFdCbHost;
|
||||
m->fds.p[1].fd = STDOUT_FILENO;
|
||||
m->fds.p[1].cb = &kMachineFdCbHost;
|
||||
m->fds.p[2].fd = STDERR_FILENO;
|
||||
m->fds.p[2].cb = &kMachineFdCbHost;
|
||||
m->fds.p = xcalloc((m->fds.n = 8), sizeof(struct MachineFd));
|
||||
AddHostFd(m, STDIN_FILENO);
|
||||
AddHostFd(m, STDOUT_FILENO);
|
||||
AddHostFd(m, STDERR_FILENO);
|
||||
if (!(rc = setjmp(m->onhalt))) {
|
||||
for (;;) {
|
||||
LoadInstruction(m);
|
||||
|
|
|
@ -248,7 +248,6 @@ int main(int argc, char *argv[]) {
|
|||
void *rgb;
|
||||
size_t size;
|
||||
unsigned yn, xn;
|
||||
cancolor();
|
||||
GetTermSize(&yn, &xn);
|
||||
yn *= 2;
|
||||
size = yn * xn * 4;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/color.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/cpuid4.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
|
@ -30,9 +31,6 @@
|
|||
#include "tool/decode/lib/idname.h"
|
||||
#include "tool/decode/lib/x86idnames.h"
|
||||
|
||||
#define RED (cancolor() ? "\x1b[91m" : "")
|
||||
#define GREEN (cancolor() ? "\x1b[32m" : "")
|
||||
#define RESET (cancolor() ? "\x1b[0m" : "")
|
||||
#define CANIUSE(FEATURE) caniuse(#FEATURE, X86_HAVE(FEATURE))
|
||||
#define SHOW(CONSTANT) show(#CONSTANT, CONSTANT)
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include "dsp/tty/tty.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/color.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
|
@ -21,10 +23,10 @@
|
|||
#define WRITE(s) write(STDOUT_FILENO, s, strlen(s))
|
||||
|
||||
struct Sphere {
|
||||
double cx, cy, cz, r;
|
||||
long double cx, cy, cz, r;
|
||||
};
|
||||
|
||||
const char *kShades[] = {
|
||||
static const char *kShades[] = {
|
||||
"\e[48;5;232m ", "\e[48;5;233m ", "\e[48;5;234m ", "\e[48;5;235m ",
|
||||
"\e[48;5;236m ", "\e[48;5;237m ", "\e[48;5;238m ", "\e[48;5;239m ",
|
||||
"\e[48;5;240m ", "\e[48;5;241m ", "\e[48;5;242m ", "\e[48;5;243m ",
|
||||
|
@ -33,52 +35,53 @@ const char *kShades[] = {
|
|||
"\e[48;5;252m ", "\e[48;5;253m ", "\e[48;5;254m ", "\e[48;5;255m ",
|
||||
};
|
||||
|
||||
jmp_buf jb_;
|
||||
double light_[3] = {-50, 0, 50};
|
||||
struct Sphere pos_ = {11, 11, 11, 11};
|
||||
struct Sphere neg_ = {1, 1, -4, 11};
|
||||
static jmp_buf jb_;
|
||||
static long double light_[3] = {-50, 0, 50};
|
||||
static struct Sphere pos_ = {11, 11, 11, 11};
|
||||
static struct Sphere neg_ = {1, 1, -4, 11};
|
||||
|
||||
static void OnCtrlC(int sig) {
|
||||
longjmp(jb_, 1);
|
||||
}
|
||||
|
||||
static void Normalize(double v[3]) {
|
||||
double len;
|
||||
len = 1 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
static void Normalize(long double v[3]) {
|
||||
long double len;
|
||||
len = 1 / sqrtl(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
v[0] *= len;
|
||||
v[1] *= len;
|
||||
v[2] *= len;
|
||||
}
|
||||
|
||||
static double Dot(const double x[3], const double y[3]) {
|
||||
return fabs(x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
|
||||
static long double Dot(const long double x[3], const long double y[3]) {
|
||||
return fabsl(x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
|
||||
}
|
||||
|
||||
/* check if a ray (x,y, -inf)->(x, y, inf) hits a sphere; if so, return
|
||||
the intersecting z values. z1 is closer to the eye */
|
||||
static int HitSphere(struct Sphere *s, double x, double y, double z[2]) {
|
||||
double zsq;
|
||||
static int HitSphere(struct Sphere *s, long double x, long double y,
|
||||
long double z[2]) {
|
||||
long double zsq;
|
||||
x -= s->cx;
|
||||
y -= s->cy;
|
||||
zsq = s->r * s->r - (x * x + y * y);
|
||||
if (zsq < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
zsq = sqrt(zsq);
|
||||
zsq = sqrtl(zsq);
|
||||
z[0] = s->cz - zsq;
|
||||
z[1] = s->cz + zsq;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawSphere(double k, double ambient) {
|
||||
static void DrawSphere(long double k, long double ambient) {
|
||||
int i, j, hit_result;
|
||||
double x, y, vec[3], zb[2], zs[2];
|
||||
for (i = floor(pos_.cy - pos_.r); i <= ceil(pos_.cy + pos_.r); i++) {
|
||||
y = i + .5;
|
||||
for (j = floor(pos_.cx - 2 * pos_.r); j <= ceil(pos_.cx + 2 * pos_.r);
|
||||
long double x, y, vec[3], zb[2], zs[2];
|
||||
for (i = floorl(pos_.cy - pos_.r); i <= ceill(pos_.cy + pos_.r); i++) {
|
||||
y = i + .5L;
|
||||
for (j = floorl(pos_.cx - 2 * pos_.r); j <= ceill(pos_.cx + 2 * pos_.r);
|
||||
j++) {
|
||||
x = .5 * (j - pos_.cx) + .5 + pos_.cx;
|
||||
x = .5L * (j - pos_.cx) + .5L + pos_.cx;
|
||||
if (!HitSphere(&pos_, x, y, zb)) {
|
||||
/* ray lands in blank space, draw bg */
|
||||
hit_result = 0;
|
||||
|
@ -114,10 +117,10 @@ static void DrawSphere(double k, double ambient) {
|
|||
break;
|
||||
}
|
||||
Normalize(vec);
|
||||
WRITE(
|
||||
kShades[MIN(ARRAYLEN(kShades) - 1,
|
||||
MAX(0, lround((1 - (pow(Dot(light_, vec), k) + ambient)) *
|
||||
(ARRAYLEN(kShades) - 1))))]);
|
||||
WRITE(kShades[min(
|
||||
ARRAYLEN(kShades) - 1,
|
||||
max(0, lroundl((1 - (powl(Dot(light_, vec), k) + ambient)) *
|
||||
(ARRAYLEN(kShades) - 1))))]);
|
||||
}
|
||||
WRITE("\e[0m\n");
|
||||
}
|
||||
|
@ -125,7 +128,7 @@ static void DrawSphere(double k, double ambient) {
|
|||
}
|
||||
|
||||
int main() {
|
||||
double ang;
|
||||
long double ang;
|
||||
struct termios old;
|
||||
if (cancolor()) {
|
||||
WRITE("\e[?25l");
|
||||
|
@ -134,13 +137,12 @@ int main() {
|
|||
ang = 0;
|
||||
for (;;) {
|
||||
WRITE("\e[H");
|
||||
light_[1] = cos(ang * 2);
|
||||
light_[2] = cos(ang);
|
||||
light_[0] = sin(ang);
|
||||
light_[1] = cosl(ang * 2);
|
||||
sincosl(ang, &light_[0], &light_[2]);
|
||||
Normalize(light_);
|
||||
ang += .05;
|
||||
DrawSphere(1.5, .01);
|
||||
usleep(1. / FRAMERATE * 1e6);
|
||||
ang += .05L;
|
||||
DrawSphere(1.5L, .01L);
|
||||
usleep(1.L / FRAMERATE * 1e6);
|
||||
}
|
||||
}
|
||||
WRITE("\e[0m\e[H\e[J\e[?25h");
|
||||
|
|
|
@ -590,7 +590,6 @@ int main(int argc, char *argv[]) {
|
|||
unsigned yd, xd;
|
||||
__fast_math();
|
||||
showcrashreports();
|
||||
cancolor();
|
||||
GetOpts(argc, argv);
|
||||
// if sizes are given, 2 cases:
|
||||
// - positive values: use that as the target size
|
||||
|
|
|
@ -668,7 +668,6 @@ int main(int argc, char *argv[]) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
cancolor();
|
||||
showcrashreports();
|
||||
for (i = optind; i < argc; ++i) {
|
||||
WithImageFile(argv[i], scaler);
|
||||
|
|
|
@ -399,7 +399,6 @@ void WithImageFile(const char *path,
|
|||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
cancolor();
|
||||
GetOpts(&argc, argv);
|
||||
stbi_set_unpremultiply_on_load(true);
|
||||
for (i = optind; i < argc; ++i) {
|
||||
|
|
|
@ -41,7 +41,7 @@ int main(int argc, char *argv[]) {
|
|||
r = (rgb & 0xff0000) >> 020;
|
||||
tty = rgb2tty(r, g, b);
|
||||
printf("\e[48;5;%dm \e[0m %d \\e[48;5;%dm %s #%02x%02x%02x\n", tty.xt,
|
||||
tty.xt, tty.xt, indexdoublenulstring(kXtermName, tty.xt), r, g, b);
|
||||
tty.xt, tty.xt, IndexDoubleNulString(kXtermName, tty.xt), r, g, b);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1603,7 +1603,6 @@ int main(int argc, char *argv[]) {
|
|||
sigaddset(&wut, SIGPIPE);
|
||||
sigprocmask(SIG_SETMASK, &wut, NULL);
|
||||
if (!NoDebug()) showcrashreports();
|
||||
cancolor();
|
||||
fullclear_ = true;
|
||||
GetOpts(argc, argv);
|
||||
if (!tuned_) PickDefaults();
|
||||
|
@ -1613,7 +1612,7 @@ int main(int argc, char *argv[]) {
|
|||
ffplay_ = commandvenv("FFPLAY", "ffplay");
|
||||
infd_ = STDIN_FILENO;
|
||||
outfd_ = STDOUT_FILENO;
|
||||
nullfd_ = open("/dev/null", O_APPEND | O_RDWR | O_NONBLOCK);
|
||||
nullfd_ = open("/dev/null", O_APPEND | O_RDWR);
|
||||
if (!setjmp(jb_)) {
|
||||
xsigaction(SIGINT, OnCtrlC, 0, 0, NULL);
|
||||
xsigaction(SIGHUP, OnCtrlC, 0, 0, NULL);
|
||||
|
@ -1625,11 +1624,11 @@ int main(int argc, char *argv[]) {
|
|||
__cxa_atexit(OnExit, NULL, NULL);
|
||||
g_logfile = fopen(logpath_, "a");
|
||||
if (ischardev(infd_) && ischardev(outfd_)) {
|
||||
CHECK_NE(-1, fcntl(infd_, F_SETFL, O_NONBLOCK));
|
||||
/* CHECK_NE(-1, fcntl(infd_, F_SETFL, O_NONBLOCK)); */
|
||||
} else if (infd_ != outfd_) {
|
||||
infd_ = -1;
|
||||
}
|
||||
CHECK_NE(-1, fcntl(outfd_, F_SETFL, O_NONBLOCK));
|
||||
/* CHECK_NE(-1, fcntl(outfd_, F_SETFL, O_NONBLOCK)); */
|
||||
if (CanPlayAudio()) MakeLatencyLittleLessBad();
|
||||
TryToOpenFrameBuffer();
|
||||
RenounceSpecialPrivileges();
|
||||
|
|
|
@ -700,7 +700,7 @@ int main(int argc, char *argv[]) {
|
|||
for (i = 0; i < 256; ++i) {
|
||||
printf("\e[48;5;%dm \e[0m \e[38;5;%dm██\e[0m \e[1;48;5;%dm "
|
||||
"\e[0m \e[1;38;5;%dm██\e[0m %-6hhu%-18s#%02hhx%02hhx%02hhx\n",
|
||||
i, i, i, i, i, indexdoublenulstring(kXtermName, i), kXtermRgb[i].r,
|
||||
i, i, i, i, i, IndexDoubleNulString(kXtermName, i), kXtermRgb[i].r,
|
||||
kXtermRgb[i].g, kXtermRgb[i].b);
|
||||
}
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue