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:
Justine Tunney 2022-03-16 13:33:13 -07:00
parent 2a938b3eaa
commit b45d50b690
194 changed files with 4881 additions and 2966 deletions

View file

@ -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())) {

View file

@ -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);
}

View file

@ -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;

View file

@ -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");

View file

@ -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? */

View file

@ -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);

View file

@ -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 *);

View file

@ -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;
}

View file

@ -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);

View file

@ -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,

View file

@ -13,6 +13,7 @@
#define kMachineFpuException -7
#define kMachineProtectionFault -8
#define kMachineSimdException -9
#define kMachineOverflow -10
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

View file

@ -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 {

View file

@ -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;
}

View file

@ -102,6 +102,7 @@
const struct MachineFdCb kMachineFdCbHost = {
.close = close,
.readv = readv,
.poll = poll,
.writev = writev,
.ioctl = (void *)ioctl,
};

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);
}