mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-25 03:50:29 +00:00
Make improvements
- Fix build flakes - Polyfill SIGWINCH on Windows - Fix an execve issue on Windows - Make strerror show more information - Improve cmd.exe setup/teardown on Windows - Support bracketed paste mode in Blinkenlights - Show keyboard shortcuts in Blinkenlights status bar - Fixed copy_file_range() and copyfile() w/ zip filesystem - Size optimize GetDosArgv() to keep life.com 12kb in size - Improve Blinkenlights ability to load weird ELF executables - Fix program_executable_name and add GetInterpreterExecutableName - Make Python in tiny mode fail better if docstrings are requested - Update Python test exclusions in tiny* modes such as tinylinux - Add bulletproof unbreakable kprintf() troubleshooting function - Remove "oldskool" keyword from ape.S for virus scanners - Fix issue that caused backtraces to not print sometimes - Improve Blinkenlights serial uart character i/o - Make clock_gettime() not clobber errno on xnu - Improve sha256 cpuid check for old computers - Integrate some bestline linenoise fixes - Show runit process names better in htop - Remove SIGPIPE from ShowCrashReports() - Make realpath() not clobber errno - Avoid attaching GDB on non-Linux - Improve img.com example
This commit is contained in:
parent
2a938b3eaa
commit
b45d50b690
194 changed files with 4881 additions and 2966 deletions
|
@ -30,6 +30,7 @@
|
|||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/bing.internal.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
@ -37,15 +38,18 @@
|
|||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/pcmpeqb.h"
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
|
@ -198,6 +202,12 @@ struct MemoryView {
|
|||
int zoom;
|
||||
};
|
||||
|
||||
struct Keystrokes {
|
||||
unsigned i;
|
||||
char p[4][32];
|
||||
long double s[4];
|
||||
};
|
||||
|
||||
struct MachineState {
|
||||
uint64_t ip;
|
||||
uint8_t cs[8];
|
||||
|
@ -296,6 +306,7 @@ static struct Pty *pty;
|
|||
static struct Machine *m;
|
||||
|
||||
static struct Panels pan;
|
||||
static struct Keystrokes keystrokes;
|
||||
static struct Breakpoints breakpoints;
|
||||
static struct MemoryView codeview;
|
||||
static struct MemoryView readview;
|
||||
|
@ -545,6 +556,10 @@ static void ShowCursor(void) {
|
|||
TtyWriteString("\e[?25h");
|
||||
}
|
||||
|
||||
static void EnableSafePaste(void) {
|
||||
TtyWriteString("\e[?2004h");
|
||||
}
|
||||
|
||||
static void DisableSafePaste(void) {
|
||||
TtyWriteString("\e[?2004l");
|
||||
}
|
||||
|
@ -596,7 +611,7 @@ static void TuiRejuvinate(void) {
|
|||
CHECK_NE(-1, ioctl(ttyout, TCSETS, &term));
|
||||
xsigaction(SIGBUS, OnSigBusted, SA_NODEFER, 0, NULL);
|
||||
EnableMouseTracking();
|
||||
DisableSafePaste();
|
||||
EnableSafePaste();
|
||||
}
|
||||
|
||||
static void OnQ(void) {
|
||||
|
@ -639,12 +654,14 @@ static void TtyRestore2(void) {
|
|||
DEBUGF("TtyRestore2");
|
||||
ioctl(ttyout, TCSETS, &oldterm);
|
||||
DisableMouseTracking();
|
||||
DisableSafePaste();
|
||||
}
|
||||
|
||||
static void TuiCleanup(void) {
|
||||
sigaction(SIGCONT, oldsig + 2, NULL);
|
||||
TtyRestore1();
|
||||
DisableMouseTracking();
|
||||
DisableSafePaste();
|
||||
tuimode = false;
|
||||
LeaveScreen();
|
||||
}
|
||||
|
@ -682,12 +699,14 @@ static void LoadSyms(void) {
|
|||
static int DrainInput(int fd) {
|
||||
char buf[32];
|
||||
struct pollfd fds[1];
|
||||
for (;;) {
|
||||
fds[0].fd = fd;
|
||||
fds[0].events = POLLIN;
|
||||
if (poll(fds, ARRAYLEN(fds), 0) == -1) return -1;
|
||||
if (!(fds[0].revents & POLLIN)) break;
|
||||
if (read(fd, buf, sizeof(buf)) == -1) return -1;
|
||||
if (!IsWindows()) {
|
||||
for (;;) {
|
||||
fds[0].fd = fd;
|
||||
fds[0].events = POLLIN;
|
||||
if (poll(fds, ARRAYLEN(fds), 0) == -1) return -1;
|
||||
if (!(fds[0].revents & POLLIN)) break;
|
||||
if (read(fd, buf, sizeof(buf)) == -1) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1602,6 +1621,34 @@ static int AppendStat(struct Buffer *b, const char *name, int64_t value,
|
|||
return 1 + width;
|
||||
}
|
||||
|
||||
static char *GetStatus(int m) {
|
||||
bool first;
|
||||
char *b = 0;
|
||||
unsigned i, n;
|
||||
long double t;
|
||||
if (statusmessage && nowl() < statusexpires) {
|
||||
appends(&b, statusmessage);
|
||||
} else {
|
||||
appends(&b, "das blinkenlights");
|
||||
}
|
||||
n = ARRAYLEN(keystrokes.p);
|
||||
for (first = true, t = nowl(), i = 1; i <= n; --i) {
|
||||
if (!keystrokes.p[(keystrokes.i - i) % n][0]) continue;
|
||||
if (t - keystrokes.s[(keystrokes.i - i) % n] > 1) continue;
|
||||
if (first) {
|
||||
first = false;
|
||||
appends(&b, " (keystroke: ");
|
||||
} else {
|
||||
appendw(&b, ' ');
|
||||
}
|
||||
appends(&b, keystrokes.p[(keystrokes.i - i) % n]);
|
||||
}
|
||||
if (!first) {
|
||||
appendw(&b, ')');
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
static void DrawStatus(struct Panel *p) {
|
||||
int yn, xn, rw;
|
||||
struct Buffer *s;
|
||||
|
@ -1621,9 +1668,7 @@ static void DrawStatus(struct Panel *p) {
|
|||
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",
|
||||
AppendFmt(&p->lines[0], "\e[7m%-*s%s\e[0m", xn - rw, gc(GetStatus(xn - rw)),
|
||||
s->p);
|
||||
free(s->p);
|
||||
free(s);
|
||||
|
@ -1700,6 +1745,29 @@ static void ReactiveDraw(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void DescribeKeystroke(char *b, const char *p) {
|
||||
int c;
|
||||
do {
|
||||
c = *p++ & 255;
|
||||
if (c == '\e') {
|
||||
b = stpcpy(b, "ALT-");
|
||||
c = *p++ & 255;
|
||||
}
|
||||
if (c <= 32) {
|
||||
b = stpcpy(b, "CTRL-");
|
||||
c = CTRL(c);
|
||||
}
|
||||
*b++ = c;
|
||||
*b = 0;
|
||||
} while (*p);
|
||||
}
|
||||
|
||||
static void RecordKeystroke(const char *k) {
|
||||
keystrokes.s[keystrokes.i] = nowl();
|
||||
DescribeKeystroke(keystrokes.p[keystrokes.i], k);
|
||||
keystrokes.i = (keystrokes.i + 1) % ARRAYLEN(keystrokes.p);
|
||||
}
|
||||
|
||||
static void HandleAlarm(void) {
|
||||
alarmed = false;
|
||||
action &= ~ALARM;
|
||||
|
@ -1719,6 +1787,8 @@ static void HandleAppReadInterrupt(void) {
|
|||
}
|
||||
if (action & INT) {
|
||||
action &= ~INT;
|
||||
RecordKeystroke("\3");
|
||||
ReactiveDraw();
|
||||
if (action & CONTINUE) {
|
||||
action &= ~CONTINUE;
|
||||
} else {
|
||||
|
@ -1770,33 +1840,47 @@ static struct Mouse ParseMouse(char *p) {
|
|||
return m;
|
||||
}
|
||||
|
||||
static ssize_t ReadPtyFdDirect(int fd, void *data, size_t size) {
|
||||
static ssize_t ReadAnsi(int fd, char *p, size_t n) {
|
||||
ssize_t rc;
|
||||
char buf[32];
|
||||
struct Mouse m;
|
||||
DEBUGF("ReadPtyFdDirect");
|
||||
pty->conf |= kPtyBlinkcursor;
|
||||
for (;;) {
|
||||
ReactiveDraw();
|
||||
if ((rc = readansi(fd, buf, sizeof(buf))) != -1) {
|
||||
if (tuimode && rc > 3 &&
|
||||
(buf[0] == '\e' && buf[1] == '[' && buf[2] == '<')) {
|
||||
m = ParseMouse(buf + 3);
|
||||
if (LocatePanel(m.y, m.x) != &pan.display) {
|
||||
HandleKeyboard(buf);
|
||||
if ((rc = readansi(fd, p, n)) != -1) {
|
||||
if (tuimode && rc > 3 && p[0] == '\e' && p[1] == '[') {
|
||||
if (p[2] == '2' && p[3] == '0' && p[4] == '0' && p[5] == '~') {
|
||||
belay = true;
|
||||
continue;
|
||||
}
|
||||
if (p[2] == '2' && p[3] == '0' && p[4] == '1' && p[5] == '~') {
|
||||
belay = false;
|
||||
continue;
|
||||
}
|
||||
if (p[2] == '<') {
|
||||
m = ParseMouse(p + 3);
|
||||
if (LocatePanel(m.y, m.x) != &pan.display) {
|
||||
HandleKeyboard(p);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
return rc;
|
||||
} else {
|
||||
CHECK_EQ(EINTR, errno);
|
||||
HandleAppReadInterrupt();
|
||||
}
|
||||
CHECK_EQ(EINTR, errno);
|
||||
HandleAppReadInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t ReadPtyFdDirect(int fd) {
|
||||
ssize_t rc;
|
||||
char buf[32];
|
||||
pty->conf |= kPtyBlinkcursor;
|
||||
rc = ReadAnsi(fd, buf, sizeof(buf));
|
||||
pty->conf &= ~kPtyBlinkcursor;
|
||||
if (rc > 0) {
|
||||
PtyWriteInput(pty, buf, rc);
|
||||
ReactiveDraw();
|
||||
rc = PtyRead(pty, data, size);
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -1814,15 +1898,62 @@ static ssize_t OnPtyFdReadv(int fd, const struct iovec *iov, int iovlen) {
|
|||
}
|
||||
}
|
||||
if (size) {
|
||||
if (!(rc = PtyRead(pty, data, size))) {
|
||||
rc = ReadPtyFdDirect(fd, data, size);
|
||||
for (;;) {
|
||||
if ((rc = PtyRead(pty, data, size))) {
|
||||
return rc;
|
||||
}
|
||||
if (ReadPtyFdDirect(fd) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int OnPtyFdPoll(struct pollfd *fds, size_t nfds, int ms) {
|
||||
bool once, rem;
|
||||
int i, t, re, rc;
|
||||
struct pollfd p2;
|
||||
ms &= INT_MAX;
|
||||
for (once = t = i = 0; i < nfds; ++i) {
|
||||
re = 0;
|
||||
if (fds[i].fd >= 0) {
|
||||
if (pty->input.i) {
|
||||
re = POLLIN | POLLOUT;
|
||||
++t;
|
||||
} else {
|
||||
if (!once) {
|
||||
ReactiveDraw();
|
||||
once = true;
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
p2.fd = fds[i].fd;
|
||||
p2.events = fds[i].events;
|
||||
switch (poll(&p2, 1, ms)) {
|
||||
case -1:
|
||||
re = POLLERR;
|
||||
++t;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
re = p2.revents;
|
||||
++t;
|
||||
break;
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
} else {
|
||||
re = POLLIN | POLLOUT; /* xxx */
|
||||
}
|
||||
}
|
||||
}
|
||||
fds[i].revents = re;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static void DrawDisplayOnly(struct Panel *p) {
|
||||
struct Buffer b;
|
||||
int i, y, yn, xn, tly, tlx, conf;
|
||||
|
@ -1910,6 +2041,7 @@ static const struct MachineFdCb kMachineFdCbPty = {
|
|||
.readv = OnPtyFdReadv,
|
||||
.writev = OnPtyFdWritev,
|
||||
.ioctl = OnPtyFdIoctl,
|
||||
.poll = OnPtyFdPoll,
|
||||
};
|
||||
|
||||
static void LaunchDebuggerReactively(void) {
|
||||
|
@ -2137,11 +2269,10 @@ static void OnVidyaServiceTeletypeOutput(void) {
|
|||
int n;
|
||||
uint64_t w;
|
||||
char buf[12];
|
||||
n = FormatCga(m->bx[0], buf);
|
||||
n = 0 /* FormatCga(m->bx[0], buf) */;
|
||||
w = tpenc(VidyaServiceXlatTeletype(m->ax[0]));
|
||||
do {
|
||||
buf[n++] = w;
|
||||
} while ((w >>= 8));
|
||||
do buf[n++] = w;
|
||||
while ((w >>= 8));
|
||||
PtyWrite(pty, buf, n);
|
||||
}
|
||||
|
||||
|
@ -2173,64 +2304,19 @@ static void OnVidyaService(void) {
|
|||
static void OnKeyboardServiceReadKeyPress(void) {
|
||||
wint_t x;
|
||||
uint8_t b;
|
||||
ssize_t rc;
|
||||
size_t i, n;
|
||||
struct Mouse mo;
|
||||
static char buf[32];
|
||||
static size_t pending;
|
||||
static const char *fun;
|
||||
static const char *prog /* = "(CONS (QUOTE A) (QUOTE B))" */;
|
||||
pty->conf |= kPtyBlinkcursor;
|
||||
if (!fun && prog) {
|
||||
fun = prog;
|
||||
belay = 1;
|
||||
}
|
||||
if (fun && *fun) {
|
||||
b = *fun++;
|
||||
if (!*fun) {
|
||||
ReactiveDraw();
|
||||
belay = 0;
|
||||
}
|
||||
} else {
|
||||
if (!pending) {
|
||||
for (;;) {
|
||||
ReactiveDraw();
|
||||
if ((rc = readansi(0, buf, sizeof(buf))) != -1) {
|
||||
if (!rc) {
|
||||
exitcode = 0;
|
||||
action |= EXIT;
|
||||
return;
|
||||
}
|
||||
if (!memcmp(buf, "\e[200~", 6) || !memcmp(buf, "\e[201~", 6)) {
|
||||
continue;
|
||||
}
|
||||
if ((x = buf[0] & 0377) >= 0300) {
|
||||
n = ThomPikeLen(x);
|
||||
x = ThomPikeByte(x);
|
||||
for (i = 1; i < n; ++i) {
|
||||
x = ThomPikeMerge(x, buf[i] & 0377);
|
||||
}
|
||||
buf[0] = unbing(x);
|
||||
rc = 1;
|
||||
} else if (tuimode && rc > 3 &&
|
||||
(buf[0] == '\e' && buf[1] == '[' && buf[2] == '<')) {
|
||||
mo = ParseMouse(buf + 3);
|
||||
if (LocatePanel(mo.y, mo.x) != &pan.display) {
|
||||
HandleKeyboard(buf);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
pending = rc;
|
||||
break;
|
||||
}
|
||||
CHECK_EQ(EINTR, errno);
|
||||
HandleAppReadInterrupt();
|
||||
}
|
||||
}
|
||||
b = buf[0];
|
||||
memmove(buf, buf + 1, pending - 1);
|
||||
--pending;
|
||||
if (!pending && !(pending = ReadAnsi(0, buf, sizeof(buf)))) {
|
||||
exitcode = 0;
|
||||
action |= EXIT;
|
||||
return;
|
||||
}
|
||||
b = buf[0];
|
||||
memmove(buf, buf + 1, pending - 1);
|
||||
--pending;
|
||||
pty->conf &= ~kPtyBlinkcursor;
|
||||
ReactiveDraw();
|
||||
if (b == 0x7F) b = '\b';
|
||||
|
@ -2521,7 +2607,11 @@ static bool HasPendingKeyboard(void) {
|
|||
}
|
||||
|
||||
static void Sleep(int ms) {
|
||||
poll((struct pollfd[]){{ttyin, POLLIN}}, 1, ms);
|
||||
if (IsWindows()) {
|
||||
usleep(ms * 1000L);
|
||||
} else {
|
||||
poll((struct pollfd[]){{ttyin, POLLIN}}, 1, ms);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnMouseWheelUp(struct Panel *p, int y, int x) {
|
||||
|
@ -2596,7 +2686,8 @@ static void OnHelp(void) {
|
|||
dialog = HELP;
|
||||
}
|
||||
|
||||
static void HandleKeyboard(const char *p) {
|
||||
static void HandleKeyboard(const char *k) {
|
||||
const char *p = k;
|
||||
switch (*p++) {
|
||||
CASE('q', OnQ());
|
||||
CASE('v', OnV());
|
||||
|
@ -2634,9 +2725,9 @@ static void HandleKeyboard(const char *p) {
|
|||
switch (*p++) {
|
||||
CASE('P', OnHelp()); /* \eOP is F1 */
|
||||
default:
|
||||
break;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
return;
|
||||
case '[':
|
||||
switch (*p++) {
|
||||
CASE('<', OnMouse(p));
|
||||
|
@ -2649,16 +2740,17 @@ static void HandleKeyboard(const char *p) {
|
|||
CASE('5', OnPageUp()); /* \e[1~ is pgup */
|
||||
CASE('6', OnPageDown()); /* \e[1~ is pgdn */
|
||||
default:
|
||||
break;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return;
|
||||
}
|
||||
RecordKeystroke(k);
|
||||
}
|
||||
|
||||
static void ReadKeyboard(void) {
|
||||
|
@ -2824,6 +2916,8 @@ static void Tui(void) {
|
|||
if (action & INT) {
|
||||
INFOF("TUI INT");
|
||||
action &= ~INT;
|
||||
RecordKeystroke("\3");
|
||||
ReactiveDraw();
|
||||
if (action & (CONTINUE | NEXT | FINISH)) {
|
||||
action &= ~(CONTINUE | NEXT | FINISH);
|
||||
} else {
|
||||
|
@ -3012,11 +3106,12 @@ static void OnlyRunOnFirstCpu(void) {
|
|||
int main(int argc, char *argv[]) {
|
||||
if (!NoDebug()) showcrashreports();
|
||||
pty = NewPty();
|
||||
pty->conf |= kPtyNocanon;
|
||||
m = NewMachine();
|
||||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
m->onbinbase = OnBinbase;
|
||||
m->onlongbranch = OnLongBranch;
|
||||
speed = 16;
|
||||
speed = 32;
|
||||
SetXmmSize(2);
|
||||
SetXmmDisp(kXmmHex);
|
||||
if ((colorize = cancolor())) {
|
||||
|
|
|
@ -28,9 +28,11 @@
|
|||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
|
@ -43,6 +45,7 @@
|
|||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -95,8 +98,8 @@ FLAGS\n\
|
|||
-T TARGET specifies target name for V=0 logging\n\
|
||||
-A ACTION specifies short command name for V=0 logging\n\
|
||||
-V NUMBER specifies compiler version\n\
|
||||
-C SECS set cpu limit [default 8]\n\
|
||||
-L SECS set lat limit [default 64]\n\
|
||||
-C SECS set cpu limit [default 16]\n\
|
||||
-L SECS set lat limit [default 90]\n\
|
||||
-M BYTES set mem limit [default 512m]\n\
|
||||
-F BYTES set fsz limit [default 100m]\n\
|
||||
-O BYTES set out limit [default 1m]\n\
|
||||
|
@ -194,6 +197,7 @@ const char *const kSafeEnv[] = {
|
|||
"MODE", // needed by test scripts
|
||||
"PATH", // needed by clang
|
||||
"PWD", // just seems plain needed
|
||||
"STRACE", // useful for troubleshooting
|
||||
"TERM", // needed by IsTerminalInarticulate
|
||||
"TMPDIR", // needed by compiler
|
||||
};
|
||||
|
@ -223,6 +227,7 @@ const char *const kGccOnlyFlags[] = {
|
|||
"-fno-gnu-unique",
|
||||
"-fno-gnu-unique",
|
||||
"-fno-instrument-functions",
|
||||
"-fno-schedule-insns2",
|
||||
"-fno-whole-program",
|
||||
"-fopt-info-vec",
|
||||
"-fopt-info-vec-missed",
|
||||
|
@ -324,10 +329,14 @@ int GetTerminalWidth(void) {
|
|||
}
|
||||
}
|
||||
|
||||
int GetLineWidth(void) {
|
||||
int GetLineWidth(bool *isineditor) {
|
||||
char *s;
|
||||
struct winsize ws = {0};
|
||||
if ((s = getenv("COLUMNS"))) {
|
||||
s = getenv("COLUMNS");
|
||||
if (isineditor) {
|
||||
*isineditor = !!s;
|
||||
}
|
||||
if (s) {
|
||||
return atoi(s);
|
||||
} else if (ioctl(2, TIOCGWINSZ, &ws) != -1) {
|
||||
if (ws.ws_col && ws.ws_row) {
|
||||
|
@ -398,11 +407,20 @@ bool FileExistsAndIsNewerThan(const char *filepath, const char *thanpath) {
|
|||
return st1.st_mtim.tv_nsec >= st2.st_mtim.tv_nsec;
|
||||
}
|
||||
|
||||
static size_t TallyArgs(char **p) {
|
||||
size_t n;
|
||||
for (n = 0; *p; ++p) {
|
||||
n += sizeof(*p);
|
||||
n += strlen(*p) + 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void AddStr(struct Strings *l, char *s) {
|
||||
l->p = realloc(l->p, (++l->n + 1) * sizeof(*l->p));
|
||||
l->p[l->n - 1] = s;
|
||||
l->p[l->n - 0] = 0;
|
||||
};
|
||||
}
|
||||
|
||||
void AddEnv(char *s) {
|
||||
AddStr(&env, s);
|
||||
|
@ -433,7 +451,15 @@ void AddArg(char *s) {
|
|||
} else {
|
||||
appends(&shortened, s);
|
||||
}
|
||||
} else if (s[0] == '-' && (!s[1] || s[1] == 'o' || (s[1] == '-' && !s[2]) ||
|
||||
} else if (/*
|
||||
* a in ('-', '--') or
|
||||
* a.startswith('-o') or
|
||||
* c == 'ld' and a == '-T' or
|
||||
* c == 'cc' and a.startswith('-O') or
|
||||
* c == 'cc' and a.startswith('-x') or
|
||||
* c == 'cc' and a in ('-c', '-E', '-S')
|
||||
*/
|
||||
s[0] == '-' && (!s[1] || s[1] == 'o' || (s[1] == '-' && !s[2]) ||
|
||||
(isbfd && (s[1] == 'T' && !s[2])) ||
|
||||
(iscc && (s[1] == 'O' || s[1] == 'x' ||
|
||||
(!s[2] && (s[1] == 'c' || s[1] == 'E' ||
|
||||
|
@ -486,6 +512,56 @@ void SetMemLimit(long n) {
|
|||
setrlimit(RLIMIT_AS, &rlim);
|
||||
}
|
||||
|
||||
bool ArgNeedsShellQuotes(const char *s) {
|
||||
if (*s) {
|
||||
for (;;) {
|
||||
switch (*s++ & 255) {
|
||||
case 0:
|
||||
return false;
|
||||
case '-':
|
||||
case '.':
|
||||
case '/':
|
||||
case '_':
|
||||
case '=':
|
||||
case ':':
|
||||
case '0' ... '9':
|
||||
case 'A' ... 'Z':
|
||||
case 'a' ... 'z':
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
char *AddShellQuotes(const char *s) {
|
||||
char *p, *q;
|
||||
size_t i, j, n;
|
||||
n = strlen(s);
|
||||
p = malloc(1 + n * 5 + 1 + 1);
|
||||
j = 0;
|
||||
p[j++] = '\'';
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (s[i] != '\'') {
|
||||
p[j++] = s[i];
|
||||
} else {
|
||||
p[j + 0] = '\'';
|
||||
p[j + 1] = '"';
|
||||
p[j + 2] = '\'';
|
||||
p[j + 3] = '"';
|
||||
p[j + 4] = '\'';
|
||||
j += 5;
|
||||
}
|
||||
}
|
||||
p[j++] = '\'';
|
||||
p[j] = 0;
|
||||
if ((q = realloc(p, j + 1))) p = q;
|
||||
return p;
|
||||
}
|
||||
|
||||
int Launch(void) {
|
||||
size_t got;
|
||||
ssize_t rc;
|
||||
|
@ -499,7 +575,19 @@ int Launch(void) {
|
|||
timer.it_interval.tv_sec = timeout;
|
||||
setitimer(ITIMER_REAL, &timer, 0);
|
||||
}
|
||||
if ((pid = vfork()) == -1) exit(errno);
|
||||
pid = fork();
|
||||
|
||||
#if 0
|
||||
int fd;
|
||||
size_t n;
|
||||
char b[1024], *p;
|
||||
size_t t = strlen(cmd) + 1 + TallyArgs(args.p) + 9 + TallyArgs(env.p) + 9;
|
||||
n = ksnprintf(b, sizeof(b), "%ld %s %s\n", t, cmd, outpath);
|
||||
fd = open("o/argmax.txt", O_APPEND | O_CREAT | O_WRONLY, 0644);
|
||||
write(fd, b, n);
|
||||
close(fd);
|
||||
#endif
|
||||
|
||||
if (!pid) {
|
||||
SetCpuLimit(cpuquota);
|
||||
SetFszLimit(fszquota);
|
||||
|
@ -508,7 +596,7 @@ int Launch(void) {
|
|||
dup2(pipefds[1], 2);
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
execve(cmd, args.p, env.p);
|
||||
_exit(127);
|
||||
_Exit(127);
|
||||
}
|
||||
close(pipefds[1]);
|
||||
for (;;) {
|
||||
|
@ -609,21 +697,42 @@ void ReportResources(void) {
|
|||
appendw(&output, '\n');
|
||||
}
|
||||
|
||||
bool IsNativeExecutable(const char *path) {
|
||||
bool res;
|
||||
char buf[4];
|
||||
int got, fd;
|
||||
res = false;
|
||||
if ((fd = open(path, O_RDONLY)) != -1) {
|
||||
if ((got = read(fd, buf, 4)) == 4) {
|
||||
if (IsWindows()) {
|
||||
res = READ16LE(buf) == READ16LE("MZ");
|
||||
} else if (IsXnu()) {
|
||||
res = READ32LE(buf) == 0xFEEDFACEu + 1;
|
||||
} else {
|
||||
res = READ32LE(buf) == READ32LE("\177ELF");
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int columns;
|
||||
uint64_t us;
|
||||
bool isineditor;
|
||||
size_t i, j, n, m;
|
||||
bool isproblematic;
|
||||
char *s, *p, **envp;
|
||||
int ws, opt, exitcode;
|
||||
char *s, *p, *q, **envp;
|
||||
|
||||
/*
|
||||
* parse prefix arguments
|
||||
*/
|
||||
mode = MODE;
|
||||
verbose = 4;
|
||||
timeout = 64; /* secs */
|
||||
cpuquota = 8; /* secs */
|
||||
timeout = 90; /* secs */
|
||||
cpuquota = 16; /* secs */
|
||||
fszquota = 100 * 1000 * 1000; /* bytes */
|
||||
memquota = 512 * 1024 * 1024; /* bytes */
|
||||
if ((s = getenv("V"))) verbose = atoi(s);
|
||||
|
@ -876,6 +985,8 @@ int main(int argc, char *argv[]) {
|
|||
if (wantframe) {
|
||||
AddArg("-fno-omit-frame-pointer");
|
||||
AddArg("-D__FNO_OMIT_FRAME_POINTER__");
|
||||
} else {
|
||||
AddArg("-fomit-frame-pointer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -938,6 +1049,7 @@ int main(int argc, char *argv[]) {
|
|||
exit(97);
|
||||
}
|
||||
}
|
||||
args.p[0] = cmd;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -991,7 +1103,8 @@ int main(int argc, char *argv[]) {
|
|||
* cleanup temporary copy of ape executable
|
||||
*/
|
||||
if (originalcmd) {
|
||||
if (cachedcmd && WIFEXITED(ws) && !WEXITSTATUS(ws)) {
|
||||
if (cachedcmd && WIFEXITED(ws) && !WEXITSTATUS(ws) &&
|
||||
IsNativeExecutable(cmd)) {
|
||||
makedirs(xdirname(cachedcmd), 0755);
|
||||
rename(cmd, cachedcmd);
|
||||
} else {
|
||||
|
@ -1036,6 +1149,17 @@ int main(int argc, char *argv[]) {
|
|||
appends(&output, strsignal(WTERMSIG(ws)));
|
||||
PrintReset();
|
||||
appendw(&output, READ16LE(":\n"));
|
||||
appends(&output, "env -i ");
|
||||
for (i = 0; i < env.n; ++i) {
|
||||
if (ArgNeedsShellQuotes(env.p[i])) {
|
||||
q = AddShellQuotes(env.p[i]);
|
||||
appends(&output, q);
|
||||
free(q);
|
||||
} else {
|
||||
appends(&output, env.p[i]);
|
||||
}
|
||||
appendw(&output, ' ');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exitcode = 89;
|
||||
|
@ -1170,10 +1294,19 @@ int main(int argc, char *argv[]) {
|
|||
if (verbose < 2 || verbose == 3) {
|
||||
command = shortened;
|
||||
}
|
||||
m = GetLineWidth();
|
||||
m = GetLineWidth(&isineditor);
|
||||
if (m > n + 3 && appendz(command).i > m - n) {
|
||||
appendd(&output, command, m - n - 3);
|
||||
appendw(&output, READ32LE("..."));
|
||||
if (isineditor) {
|
||||
if (m > n + 3 && appendz(shortened).i > m - n) {
|
||||
appendd(&output, shortened, m - n - 3);
|
||||
appendw(&output, READ32LE("..."));
|
||||
} else {
|
||||
appendd(&output, shortened, appendz(shortened).i);
|
||||
}
|
||||
} else {
|
||||
appendd(&output, command, m - n - 3);
|
||||
appendw(&output, READ32LE("..."));
|
||||
}
|
||||
} else {
|
||||
appendd(&output, command, appendz(command).i);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
|
||||
|
@ -86,8 +87,7 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
|
|||
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)) {
|
||||
!IsLegalPointer(st[i].st_value)) {
|
||||
continue;
|
||||
}
|
||||
isabs = st[i].st_shndx == SHN_ABS;
|
||||
|
|
|
@ -237,6 +237,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0xCB, "lret");
|
||||
RCASE(0xCC, "int3");
|
||||
RCASE(0xCD, "int Ib");
|
||||
RCASE(0xCE, "into");
|
||||
RCASE(0xCF, "iret");
|
||||
RCASE(0xD0, "BIT Eb");
|
||||
RCASE(0xD1, "BIT Evqp");
|
||||
RCASE(0xD2, "BIT Evqp %cl");
|
||||
|
|
|
@ -159,6 +159,25 @@ void EzHandshake(void) {
|
|||
}
|
||||
}
|
||||
|
||||
int EzHandshake2(void) {
|
||||
int rc;
|
||||
while ((rc = mbedtls_ssl_handshake(&ezssl))) {
|
||||
if (rc == MBEDTLS_ERR_NET_CONN_RESET) {
|
||||
return rc;
|
||||
} else if (rc != MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
TlsDie("handshake failed", rc);
|
||||
}
|
||||
}
|
||||
while ((rc = EzTlsFlush(&ezbio, 0, 0))) {
|
||||
if (rc == MBEDTLS_ERR_NET_CONN_RESET) {
|
||||
return rc;
|
||||
} else if (rc != MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
TlsDie("handshake flush failed", rc);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EzInitialize(void) {
|
||||
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
|
||||
ezconf.disable_compression = 1; /* TODO(jart): Why does it behave weirdly? */
|
||||
|
|
|
@ -20,6 +20,7 @@ extern mbedtls_ctr_drbg_context ezrng;
|
|||
|
||||
void EzFd(int);
|
||||
void EzHandshake(void);
|
||||
int EzHandshake2(void);
|
||||
void EzSetup(char[32]);
|
||||
void EzInitialize(void);
|
||||
int EzTlsFlush(struct EzTlsBio *, const unsigned char *, size_t);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -14,17 +15,18 @@ struct MachineFdCb {
|
|||
ssize_t (*readv)(int, const struct iovec *, int);
|
||||
ssize_t (*writev)(int, const struct iovec *, int);
|
||||
int (*ioctl)(int, uint64_t, void *);
|
||||
int (*poll)(struct pollfd *, uint64_t, int32_t);
|
||||
};
|
||||
|
||||
struct MachineFd {
|
||||
int fd;
|
||||
struct MachineFdCb * cb;
|
||||
struct MachineFdCb *cb;
|
||||
};
|
||||
|
||||
struct MachineFds {
|
||||
size_t i, n;
|
||||
struct MachineFd * p;
|
||||
struct MachineFdClosed * closed;
|
||||
struct MachineFd *p;
|
||||
struct MachineFdClosed *closed;
|
||||
};
|
||||
|
||||
int MachineFdAdd(struct MachineFds *);
|
||||
|
|
|
@ -17,8 +17,12 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "tool/build/lib/ioports.h"
|
||||
|
||||
static int OpE9Read(struct Machine *m) {
|
||||
|
@ -42,7 +46,21 @@ static void OpE9Write(struct Machine *m, uint8_t b) {
|
|||
m->fds.p[fd].cb->writev(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1);
|
||||
}
|
||||
|
||||
static int OpE9Poll(struct Machine *m) {
|
||||
int fd, rc;
|
||||
struct pollfd pf;
|
||||
fd = STDIN_FILENO;
|
||||
if (fd >= m->fds.i) return -1;
|
||||
if (!m->fds.p[fd].cb) return -1;
|
||||
pf.fd = m->fds.p[fd].fd;
|
||||
pf.events = POLLIN | POLLOUT;
|
||||
rc = m->fds.p[fd].cb->poll(&pf, 1, 20);
|
||||
if (rc <= 0) return rc;
|
||||
return pf.revents;
|
||||
}
|
||||
|
||||
static int OpSerialIn(struct Machine *m, int r) {
|
||||
int p, s;
|
||||
switch (r) {
|
||||
case UART_DLL:
|
||||
if (!m->dlab) {
|
||||
|
@ -51,7 +69,15 @@ static int OpSerialIn(struct Machine *m, int r) {
|
|||
return 0x01;
|
||||
}
|
||||
case UART_LSR:
|
||||
return UART_TTYDA | UART_TTYTXR | UART_TTYIDL;
|
||||
if (IsWindows()) {
|
||||
p = POLLIN | POLLOUT; /* XXX */
|
||||
} else {
|
||||
if ((p = OpE9Poll(m)) == -1) return -1;
|
||||
}
|
||||
s = UART_TTYIDL;
|
||||
if (p & POLLIN) s |= UART_TTYDA;
|
||||
if (p & POLLOUT) s |= UART_TTYTXR;
|
||||
return s;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
|
|||
int64_t align, bsssize;
|
||||
int64_t felf, fstart, fend, vstart, vbss, vend;
|
||||
align = MAX(phdr->p_align, PAGESIZE);
|
||||
CHECK_EQ(1, popcnt(align));
|
||||
if (popcnt(align) != 1) align = 8;
|
||||
CHECK_EQ(0, (phdr->p_vaddr - phdr->p_offset) % align);
|
||||
felf = (int64_t)(intptr_t)code;
|
||||
vstart = ROUNDDOWN(phdr->p_vaddr, align);
|
||||
|
|
|
@ -288,6 +288,12 @@ static void OpJmpf(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OpInto(struct Machine *m, uint32_t rde) {
|
||||
if (GetFlag(m->flags, FLAGS_OF)) {
|
||||
HaltMachine(m, kMachineOverflow);
|
||||
}
|
||||
}
|
||||
|
||||
static relegated void OpXlatAlBbb(struct Machine *m, uint32_t rde) {
|
||||
uint64_t v;
|
||||
v = MaskAddress(Eamode(rde), Read64(m->bx) + Read8(m->ax));
|
||||
|
@ -1888,7 +1894,7 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x0CB] = OpRetf,
|
||||
[0x0CC] = OpInterrupt3,
|
||||
[0x0CD] = OpInterruptImm,
|
||||
[0x0CE] = OpUd,
|
||||
[0x0CE] = OpInto,
|
||||
[0x0CF] = OpUd,
|
||||
[0x0D0] = OpBsubi1,
|
||||
[0x0D1] = OpBsuwi1,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define kMachineFpuException -7
|
||||
#define kMachineProtectionFault -8
|
||||
#define kMachineSimdException -9
|
||||
#define kMachineOverflow -10
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
|
@ -90,7 +91,7 @@ void *FindReal(struct Machine *m, int64_t virt) {
|
|||
uint64_t table, entry, page;
|
||||
unsigned skew, level, index, i;
|
||||
if ((m->mode & 3) != XED_MODE_REAL) {
|
||||
if (-0x800000000000 <= virt && virt < 0x800000000000) {
|
||||
if (IsLegalPointer(virt)) {
|
||||
if (!(entry = FindPage(m, virt))) return NULL;
|
||||
return m->real.p + (entry & PAGE_TA) + (virt & 0xfff);
|
||||
} else {
|
||||
|
|
|
@ -1167,10 +1167,45 @@ ssize_t PtyWrite(struct Pty *pty, const void *data, size_t n) {
|
|||
}
|
||||
|
||||
ssize_t PtyWriteInput(struct Pty *pty, const void *data, size_t n) {
|
||||
PtyConcatInput(pty, data, n);
|
||||
if (!(pty->conf & kPtyNoecho)) {
|
||||
PtyWrite(pty, data, n);
|
||||
int c;
|
||||
bool cr;
|
||||
char *p;
|
||||
const char *q;
|
||||
size_t i, j, m;
|
||||
q = data;
|
||||
p = pty->input.p;
|
||||
i = pty->input.i;
|
||||
m = pty->input.n;
|
||||
if (i + n * 2 + 1 > m) {
|
||||
m = MAX(m, 8);
|
||||
do m += m >> 1;
|
||||
while (i + n * 2 + 1 > m);
|
||||
if (!(p = realloc(p, m))) {
|
||||
return -1;
|
||||
}
|
||||
pty->input.p = p;
|
||||
pty->input.n = m;
|
||||
}
|
||||
cr = i && p[i - 1] == '\r';
|
||||
for (j = 0; j < n; ++j) {
|
||||
c = q[j] & 255;
|
||||
if (c == '\r') {
|
||||
cr = true;
|
||||
} else if (cr) {
|
||||
if (c != '\n') {
|
||||
p[i++] = '\n';
|
||||
}
|
||||
cr = false;
|
||||
}
|
||||
p[i++] = c;
|
||||
}
|
||||
if (cr) {
|
||||
p[i++] = '\n';
|
||||
}
|
||||
if (!(pty->conf & kPtyNoecho)) {
|
||||
PtyWrite(pty, p + pty->input.i, i - pty->input.i);
|
||||
}
|
||||
pty->input.i = i;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
const struct MachineFdCb kMachineFdCbHost = {
|
||||
.close = close,
|
||||
.readv = readv,
|
||||
.poll = poll,
|
||||
.writev = writev,
|
||||
.ioctl = (void *)ioctl,
|
||||
};
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
@ -29,7 +31,19 @@
|
|||
*/
|
||||
|
||||
void OpPause(struct Machine *m, uint32_t rde) {
|
||||
sched_yield();
|
||||
struct pollfd pf;
|
||||
static bool once, interactive;
|
||||
if (!once) {
|
||||
interactive = isatty(0);
|
||||
once = true;
|
||||
}
|
||||
if (!IsWindows() && interactive) {
|
||||
pf.fd = 0;
|
||||
pf.events = POLLIN;
|
||||
poll(&pf, 1, 20); /* make spin loops less brutal */
|
||||
} else {
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
void OpRdtsc(struct Machine *m, uint32_t rde) {
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "third_party/xed/x86.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
#include "tool/build/lib/getargs.h"
|
||||
#include "tool/build/lib/persist.h"
|
||||
|
||||
/**
|
||||
|
@ -62,14 +63,14 @@
|
|||
*
|
||||
* This script verifies the well-formedness of dependencies, e.g.
|
||||
*
|
||||
* o/tool/build/package.com \
|
||||
* -o o/libc/stubs/stubs.pkg \
|
||||
* o/libc/stubs/{a,b,...}.o
|
||||
* o/tool/build/package.com \
|
||||
* -o o/libc/stubs/stubs.pkg \
|
||||
* o/libc/stubs/{a,b,...}.o
|
||||
*
|
||||
* o/tool/build/package.com \
|
||||
* -o o/libc/nexgen32e/nexgen32e.pkg \
|
||||
* -d o/libc/stubs/stubs.pkg \
|
||||
* o/libc/nexgen32e/{a,b,...}.o
|
||||
* o/tool/build/package.com \
|
||||
* -o o/libc/nexgen32e/nexgen32e.pkg \
|
||||
* -d o/libc/stubs/stubs.pkg \
|
||||
* o/libc/nexgen32e/{a,b,...}.o
|
||||
*
|
||||
* We want the following:
|
||||
*
|
||||
|
@ -84,21 +85,30 @@
|
|||
*
|
||||
* SECOND PURPOSE
|
||||
*
|
||||
* We want all storage to be thread-local storage. So we change
|
||||
* RIP-relative instructions to be RBX-relative, only when they
|
||||
* reference sections in the binary mutable after initialization.
|
||||
*
|
||||
* This is basically what the Go language does to implement its fiber
|
||||
* multiprocessing model. We can have this in C by appropriating all the
|
||||
* work folks put into enriching GNU C with WIN32 and ASLR lool.
|
||||
*
|
||||
* THIRD PURPOSE
|
||||
*
|
||||
* Compress read-only data sections of particularly low entropy, using
|
||||
* the most appropriate directly-linked algorithm and then inject code
|
||||
* into _init() that calls it. If the data is extremely low energy, we
|
||||
* will inject code for merging page table entries too. The overcommit
|
||||
* here is limitless.
|
||||
*
|
||||
* POSSIBLE PURPOSE
|
||||
*
|
||||
* It might be nice to have all storage to be thread-local storage. So
|
||||
* we change RIP-relative instructions to be RBX-relative, only when
|
||||
* they reference sections in the binary mutable after initialization.
|
||||
*
|
||||
* This is basically what the Go language does to implement its fiber
|
||||
* multiprocessing model. We can have this in C by appropriating all the
|
||||
* work folks put into enriching GNU C with WIN32 and ASLR lool.
|
||||
*
|
||||
* CAVEATS
|
||||
*
|
||||
* This tool monkey patches `.o` files as a side-effect since we're not
|
||||
* able to modify the GCC source code. Therefore it's VERY IMPORTANT to
|
||||
* have Makefile rules which build `.a` or `.com.dbg` *depend* upon the
|
||||
* `.pkg` rule. That way they happen in the right order. Otherwise they
|
||||
* might build binaries with compromised profiling nops at the start of
|
||||
* functions, which will almost certainly result in SIGILL.
|
||||
*/
|
||||
|
||||
#define PACKAGE_MAGIC bswap_32(0xBEEFBEEFu)
|
||||
|
@ -226,6 +236,8 @@ void WritePackage(struct Package *pkg) {
|
|||
void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
|
||||
char *argv[]) {
|
||||
long i, si, opt;
|
||||
const char *arg;
|
||||
struct GetArgs ga;
|
||||
pkg->path = -1;
|
||||
while ((opt = getopt(argc, argv, "vho:d:")) != -1) {
|
||||
switch (opt) {
|
||||
|
@ -251,10 +263,12 @@ void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
|
|||
CHECK_LT(optind, argc,
|
||||
"no objects passed to package.com; "
|
||||
"is your foo.mk $(FOO_OBJS) glob broken?");
|
||||
for (i = optind; i < argc; ++i) {
|
||||
CHECK_NE(-1, (si = concat(&pkg->strings, argv[i], strlen(argv[i]) + 1)));
|
||||
getargs_init(&ga, argv + optind);
|
||||
while ((arg = getargs_next(&ga))) {
|
||||
CHECK_NE(-1, (si = concat(&pkg->strings, arg, strlen(arg) + 1)));
|
||||
CHECK_NE(-1, append(&pkg->objects, (&(struct Object){si})));
|
||||
}
|
||||
getargs_destroy(&ga);
|
||||
}
|
||||
|
||||
void IndexSections(struct Object *obj) {
|
||||
|
@ -671,17 +685,17 @@ void Package(int argc, char *argv[], struct Package *pkg,
|
|||
}
|
||||
free(pkg->objects.p[i].sections.p);
|
||||
}
|
||||
free_s(&pkg->strings.p);
|
||||
free_s(&pkg->objects.p);
|
||||
free_s(&pkg->symbols.p);
|
||||
free_s(&deps->p);
|
||||
free(pkg->strings.p);
|
||||
free(pkg->objects.p);
|
||||
free(pkg->symbols.p);
|
||||
free(deps->p);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct Package pkg;
|
||||
struct Packages deps;
|
||||
if (argc == 2 && !strcmp(argv[1], "-n")) exit(0);
|
||||
showcrashreports();
|
||||
if (IsModeDbg()) ShowCrashReports();
|
||||
bzero(&pkg, sizeof(pkg));
|
||||
bzero(&deps, sizeof(deps));
|
||||
Package(argc, argv, &pkg, &deps);
|
||||
|
|
|
@ -22,18 +22,22 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/ipclassify.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
|
@ -110,6 +114,8 @@ char g_hostname[128];
|
|||
uint16_t g_runitdport;
|
||||
volatile bool alarmed;
|
||||
|
||||
int __sys_execve(const char *, char *const[], char *const[]) hidden;
|
||||
|
||||
static void OnAlarm(int sig) {
|
||||
alarmed = true;
|
||||
}
|
||||
|
@ -166,7 +172,7 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
|||
mkdir("o", 0755);
|
||||
CHECK_NE(-1, (lock = open(gc(xasprintf("o/lock.%s", g_hostname)),
|
||||
O_RDWR | O_CREAT, 0644)));
|
||||
CHECK_NE(-1, flock(lock, LOCK_EX));
|
||||
CHECK_NE(-1, fcntl(lock, F_SETLKW, &(struct flock){F_WRLCK}));
|
||||
CHECK_NE(-1, gettimeofday(&now, 0));
|
||||
if (!read(lock, &then, 16) || ((now.tv_sec * 1000 + now.tv_usec / 1000) -
|
||||
(then.tv_sec * 1000 + then.tv_usec / 1000)) >=
|
||||
|
@ -232,6 +238,7 @@ void DeployEphemeralRunItDaemonRemotelyViaSsh(struct addrinfo *ai) {
|
|||
} else {
|
||||
DEBUGF("nospawn %s on %s:%hu", g_runitd, g_hostname, g_runitdport);
|
||||
}
|
||||
CHECK_NE(-1, fcntl(lock, F_SETLK, &(struct flock){F_UNLCK}));
|
||||
LOGIFNEG1(close(lock));
|
||||
}
|
||||
|
||||
|
@ -376,6 +383,14 @@ drop:
|
|||
return res;
|
||||
}
|
||||
|
||||
static inline bool IsElf(const char *p, size_t n) {
|
||||
return n >= 4 && READ32LE(p) == READ32LE("\177ELF");
|
||||
}
|
||||
|
||||
static inline bool IsMachO(const char *p, size_t n) {
|
||||
return n >= 4 && READ32LE(p) == 0xFEEDFACEu + 1;
|
||||
}
|
||||
|
||||
int RunOnHost(char *spec) {
|
||||
int rc;
|
||||
char *p;
|
||||
|
@ -386,9 +401,13 @@ int RunOnHost(char *spec) {
|
|||
1);
|
||||
if (!strchr(g_hostname, '.')) strcat(g_hostname, ".test.");
|
||||
do {
|
||||
Connect();
|
||||
EzFd(g_sock);
|
||||
EzHandshake(); /* TODO(jart): Backoff on MBEDTLS_ERR_NET_CONN_RESET */
|
||||
for (;;) {
|
||||
Connect();
|
||||
EzFd(g_sock);
|
||||
if (!EzHandshake2()) break;
|
||||
WARNF("warning: got connection reset in handshake");
|
||||
close(g_sock);
|
||||
}
|
||||
SendRequest();
|
||||
} while ((rc = ReadResponse()) == -1);
|
||||
return rc;
|
||||
|
@ -403,11 +422,14 @@ bool ShouldRunInParralel(void) {
|
|||
return !IsWindows() && IsParallelBuild();
|
||||
}
|
||||
|
||||
int RunRemoteTestsInParallel(char *hosts[], int count) {
|
||||
int SpawnSubprocesses(int argc, char *argv[]) {
|
||||
sigset_t chldmask, savemask;
|
||||
int i, rc, ws, pid, *pids, exitcode;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
pids = calloc(count, sizeof(char *));
|
||||
char *args[5] = {argv[0], argv[1], argv[2]};
|
||||
argc -= 3;
|
||||
argv += 3;
|
||||
pids = calloc(argc, sizeof(int));
|
||||
ignore.sa_flags = 0;
|
||||
ignore.sa_handler = SIG_IGN;
|
||||
LOGIFNEG1(sigemptyset(&ignore.sa_mask));
|
||||
|
@ -416,13 +438,17 @@ int RunRemoteTestsInParallel(char *hosts[], int count) {
|
|||
LOGIFNEG1(sigemptyset(&chldmask));
|
||||
LOGIFNEG1(sigaddset(&chldmask, SIGCHLD));
|
||||
LOGIFNEG1(sigprocmask(SIG_BLOCK, &chldmask, &savemask));
|
||||
for (i = 0; i < count; ++i) {
|
||||
CHECK_NE(-1, (pids[i] = fork()));
|
||||
for (i = 0; i < argc; ++i) {
|
||||
args[3] = argv[i];
|
||||
fprintf(stderr, "spawning %s %s %s %s\n", args[0], args[1], args[2],
|
||||
args[3]);
|
||||
CHECK_NE(-1, (pids[i] = vfork()));
|
||||
if (!pids[i]) {
|
||||
sigaction(SIGINT, &saveint, NULL);
|
||||
sigaction(SIGQUIT, &savequit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||
_exit(RunOnHost(hosts[i]));
|
||||
xsigaction(SIGINT, SIG_DFL, 0, 0, 0);
|
||||
xsigaction(SIGQUIT, SIG_DFL, 0, 0, 0);
|
||||
sigprocmask(SIG_SETMASK, &savemask, 0);
|
||||
execve(args[0], args, environ); /* for htop */
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
for (exitcode = 0;;) {
|
||||
|
@ -431,13 +457,17 @@ int RunRemoteTestsInParallel(char *hosts[], int count) {
|
|||
if (errno == ECHILD) break;
|
||||
FATALF("wait failed");
|
||||
}
|
||||
for (i = 0; i < count; ++i) {
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (pids[i] != pid) continue;
|
||||
if (WIFEXITED(ws)) {
|
||||
DEBUGF("%s exited with %d", hosts[i], WEXITSTATUS(ws));
|
||||
if (WEXITSTATUS(ws)) {
|
||||
INFOF("%s exited with %d", argv[i], WEXITSTATUS(ws));
|
||||
} else {
|
||||
DEBUGF("%s exited with %d", argv[i], WEXITSTATUS(ws));
|
||||
}
|
||||
if (!exitcode) exitcode = WEXITSTATUS(ws);
|
||||
} else {
|
||||
DEBUGF("%s terminated with %s", hosts[i], strsignal(WTERMSIG(ws)));
|
||||
INFOF("%s terminated with %s", argv[i], strsignal(WTERMSIG(ws)));
|
||||
if (!exitcode) exitcode = 128 + WTERMSIG(ws);
|
||||
}
|
||||
break;
|
||||
|
@ -447,24 +477,36 @@ int RunRemoteTestsInParallel(char *hosts[], int count) {
|
|||
LOGIFNEG1(sigaction(SIGQUIT, &savequit, NULL));
|
||||
LOGIFNEG1(sigprocmask(SIG_SETMASK, &savemask, NULL));
|
||||
free(pids);
|
||||
kprintf("nocommit%n");
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
ShowCrashReports();
|
||||
SetupPresharedKeySsl(MBEDTLS_SSL_IS_CLIENT, GetRunitPsk());
|
||||
/* __log_level = kLogDebug; */
|
||||
__log_level = kLogDebug;
|
||||
if (argc > 1 &&
|
||||
(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
|
||||
ShowUsage(stdout, 0);
|
||||
unreachable;
|
||||
}
|
||||
if (argc < 1 + 2) ShowUsage(stderr, EX_USAGE);
|
||||
CHECK_NOTNULL(commandv(firstnonnull(getenv("SSH"), "ssh"), g_ssh));
|
||||
if (argc < 3) {
|
||||
ShowUsage(stderr, EX_USAGE);
|
||||
unreachable;
|
||||
}
|
||||
CheckExists((g_runitd = argv[1]));
|
||||
CheckExists((g_prog = argv[2]));
|
||||
if (argc == 1 + 2) return 0; /* hosts list empty */
|
||||
g_sshport = 22;
|
||||
g_runitdport = RUNITD_PORT;
|
||||
return RunRemoteTestsInParallel(&argv[3], argc - 3);
|
||||
CHECK_NOTNULL(commandv(firstnonnull(getenv("SSH"), "ssh"), g_ssh));
|
||||
if (argc == 3) {
|
||||
/* hosts list empty */
|
||||
return 0;
|
||||
} else if (argc == 4) {
|
||||
/* single host */
|
||||
SetupPresharedKeySsl(MBEDTLS_SSL_IS_CLIENT, GetRunitPsk());
|
||||
g_sshport = 22;
|
||||
g_runitdport = RUNITD_PORT;
|
||||
return RunOnHost(argv[3]);
|
||||
} else {
|
||||
/* multiple hosts */
|
||||
return SpawnSubprocesses(argc, argv);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
* - 1 byte exit status
|
||||
*/
|
||||
|
||||
#define DEATH_CLOCK_SECONDS 5
|
||||
#define DEATH_CLOCK_SECONDS 16
|
||||
|
||||
#define kLogFile "o/runitd.log"
|
||||
#define kLogMaxBytes (2 * 1000 * 1000)
|
||||
|
@ -339,6 +339,8 @@ void HandleClient(void) {
|
|||
dup2(g_devnullfd, 0);
|
||||
dup2(pipefds[1], 1);
|
||||
dup2(pipefds[1], 2);
|
||||
if (pipefds[0] > 2) close(pipefds[1]);
|
||||
if (g_devnullfd > 2) close(g_devnullfd);
|
||||
execv(g_exepath, (char *const[]){g_exepath, NULL});
|
||||
_exit(127);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue