diff --git a/ape/ape.S b/ape/ape.S index 57097e585..b60487c54 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -1511,17 +1511,20 @@ long: push $GDT_LONG_DATA xor %ebp,%ebp mov $REAL_STACK_FRAME+FRAMESIZE,%esp call __map_image - ezlea metal,ax + ezlea metal.thunk,ax jmp *%rax .endfn long // Long mode in virtual address space. // @noreturn -metal: +metal.thunk: #if USE_SYMBOL_HACK .byte 0x0f,0x1f,0207 # nop rdi binbase .long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512 #endif +/ 𝑠𝑙𝑖𝑑𝑒 + .endfn metal.thunk +metal: xor %eax,%eax # clear bss mov $ape_bss_vaddr,%edi mov $ape_bss_memsz,%ecx diff --git a/libc/x/xstrcat.c b/libc/x/xstrcat.c index 058c5aa99..280b9d318 100644 --- a/libc/x/xstrcat.c +++ b/libc/x/xstrcat.c @@ -16,8 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/safemacros.h" -#include "libc/mem/mem.h" #include "libc/str/str.h" #include "libc/x/x.h" @@ -37,26 +35,24 @@ * @see gc() */ char *(xstrcat)(const char *s, ...) { - char *p, b[2]; va_list va; - size_t i, n, n2, l; + size_t n, m; + char *p, b[2]; p = NULL; - i = n = 0; + n = 0; va_start(va, s); do { if ((intptr_t)s > 0 && (intptr_t)s <= 255) { b[0] = (unsigned char)(intptr_t)s; b[1] = '\0'; s = b; - l = 1; + m = 1; } else { - l = strlen(s); + m = strlen(s); } - if ((n2 = i + l + 16) >= n) { - p = xrealloc(p, (n = n2 + (n2 >> 1))); - } - memcpy(p + i, s, l + 1); - i += l; + p = xrealloc(p, n + m + 1); + memcpy(p + n, s, m + 1); + n += m; } while ((s = va_arg(va, const char *))); va_end(va); return p; diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 37cfc8054..fa3b3cebd 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -126,6 +126,27 @@ FEATURES\n\ 8086, 8087, i386, x86_64, SSE3, SSSE3, POPCNT, MDA, CGA, TTY\n\ \n" +#define HELP \ + "\e[1mBLINKENLIGHTS v1.o\e[22m\ + https://justine.lol/blinkenlights/\n\ +\n\ +KEYBOARD SHORTCUTS CLI FLAGS\n\ +\n\ +ctrl-c interrupt -t tui mode\n\ +s step -r real mode\n\ +n next -s statistics\n\ +c continue -b ADDR push breakpoint\n\ +q quit -L PATH log file location\n\ +f finish -R reactive tui mode\n\ +R restart -H disable highlighting\n\ +x hex -v increase verbosity\n\ +? help -? help\n\ +t sse type\n\ +w sse width\n\ +B pop breakpoint\n\ +ctrl-t turbo\n\ +alt-t slowmo" + #define MAXZOOM 16 #define DUMPWIDTH 64 #define DISPWIDTH 80 @@ -255,17 +276,18 @@ static int64_t breakpointsstart; static uint64_t last_opcount; static char *codepath; static void *onbusted; +static char *dialog; static char *statusmessage; static struct Pty *pty; static struct Machine *m; static struct Panels pan; +static struct Breakpoints breakpoints; static struct MemoryView codeview; static struct MemoryView readview; static struct MemoryView writeview; static struct MemoryView stackview; static struct MachineState laststate; -static struct Breakpoints breakpoints; static struct MachineMemstat lastmemstat; static struct XmmType xmmtype; static struct Elf elf[1]; @@ -424,15 +446,24 @@ static void CopyMachineState(struct MachineState *ms) { memcpy(&ms->sse, &m->sse, sizeof(m->sse)); } +/** + * Handles file mapped page faults in valid page but past eof. + */ static void OnSigBusted(void) { CHECK(onbusted); longjmp(onbusted, 1); } +/** + * Returns true if 𝑣 is a shadow memory virtual address. + */ static bool IsShadow(int64_t v) { return 0x7fff8000 <= v && v < 0x100080000000; } +/** + * Returns glyph representing byte at virtual address 𝑣. + */ static int VirtualBing(int64_t v) { int rc; uint8_t *p; @@ -451,6 +482,9 @@ static int VirtualBing(int64_t v) { return rc; } +/** + * Returns ASAN shadow uint8 concomitant to address 𝑣 or -1. + */ static int VirtualShadow(int64_t v) { int rc; char *p; @@ -547,9 +581,7 @@ static void TuiRejuvinate(void) { static void OnQ(void) { LOGF("OnQ"); - if (action & FAILURE) exit(1); - action |= INT; - breakpoints.i = 0; + action |= EXIT; } static void OnV(void) { @@ -594,6 +626,7 @@ static void TuiCleanup(void) { TtyRestore1(); DisableMouseTracking(); tuimode = false; + LeaveScreen(); } static void ResolveBreakpoints(void) { @@ -603,8 +636,10 @@ static void ResolveBreakpoints(void) { if ((sym = DisFindSymByName(dis, breakpoints.p[i].symbol)) != -1) { breakpoints.p[i].addr = dis->syms.p[sym].addr; } else { - fprintf(stderr, "error: breakpoint not found: %s\n", - breakpoints.p[i].symbol); + fprintf( + stderr, + "error: breakpoint not found: %s (out of %,ld loaded symbols)\n", + breakpoints.p[i].symbol, dis->syms.i); exit(1); } } @@ -2155,12 +2190,9 @@ static void OnBinbase(struct Machine *m) { int64_t skew; skew = m->xedd->op.disp * 512; LOGF("skew binbase %,ld @ %p", skew, GetIp()); - for (i = 0; i < dis->syms.i; ++i) { - dis->syms.p[i].addr += skew; - } - for (i = 0; i < dis->loads.i; ++i) { - dis->loads.p[i].addr += skew; - } + for (i = 0; i < dis->syms.i; ++i) dis->syms.p[i].addr += skew; + for (i = 0; i < dis->loads.i; ++i) dis->loads.p[i].addr += skew; + for (i = 0; i < breakpoints.i; ++i) breakpoints.p[i].addr += skew; Disassemble(); } @@ -2270,7 +2302,7 @@ static void OnFinish(void) { action &= ~CONTINUE; } -static void OnContinue(void) { +static void OnContinueTui(void) { action ^= CONTINUE; action &= ~STEP; action &= ~NEXT; @@ -2278,6 +2310,15 @@ static void OnContinue(void) { action &= ~FAILURE; } +static void OnContinueExec(void) { + tuimode = false; + action |= CONTINUE; + action &= ~STEP; + action &= ~NEXT; + action &= ~FINISH; + action &= ~FAILURE; +} + static void OnQuit(void) { action |= QUIT; } @@ -2394,41 +2435,41 @@ static void OnMouse(char *p) { y -= ep->top; x -= ep->left; switch (e) { - case kMouseWheelUp: - OnMouseWheelUp(ep, y, x); - break; - case kMouseWheelDown: - OnMouseWheelDown(ep, y, x); - break; - case kMouseCtrlWheelUp: - OnMouseCtrlWheelUp(ep, y, x); - break; - case kMouseCtrlWheelDown: - OnMouseCtrlWheelDown(ep, y, x); - break; + CASE(kMouseWheelUp, OnMouseWheelUp(ep, y, x)); + CASE(kMouseWheelDown, OnMouseWheelDown(ep, y, x)); + CASE(kMouseCtrlWheelUp, OnMouseCtrlWheelUp(ep, y, x)); + CASE(kMouseCtrlWheelDown, OnMouseCtrlWheelDown(ep, y, x)); default: break; } } } +static void OnHelp(void) { + DEBUGF("setting dialog"); + dialog = HELP; +} + static void ReadKeyboard(void) { char buf[64], *p = buf; memset(buf, 0, sizeof(buf)); + dialog = NULL; if (readansi(ttyin, buf, sizeof(buf)) == -1) { if (errno == EINTR) { - LOGF("readkeyboard interrupted"); + LOGF("ReadKeyboard interrupted"); return; } - FATALF("readkeyboard failed: %s", strerror(errno)); + FATALF("ReadKeyboard failed: %s", strerror(errno)); } switch (*p++) { CASE('q', OnQ()); CASE('v', OnV()); + CASE('?', OnHelp()); CASE('s', OnStep()); CASE('n', OnNext()); CASE('f', OnFinish()); - CASE('c', OnContinue()); + CASE('c', OnContinueTui()); + CASE('C', OnContinueExec()); CASE('R', OnRestart()); CASE('x', OnXmmDisp()); CASE('t', OnXmmType()); @@ -2451,57 +2492,26 @@ static void ReadKeyboard(void) { CASE(CTRL('T'), OnTurbo()); case '\e': switch (*p++) { - CASE('v', OnPageUp()); - CASE('t', OnSlowmo()); + CASE('v', OnPageUp()); /* alt+v */ + CASE('t', OnSlowmo()); /* alt+t */ + case 'O': + switch (*p++) { + CASE('P', OnHelp()); /* \eOP is F1 */ + default: + break; + } + break; case '[': switch (*p++) { CASE('<', OnMouse(p)); - CASE('A', OnUpArrow()); - CASE('B', OnDownArrow()); - CASE('F', OnEnd()); - CASE('H', OnHome()); - case '1': - switch (*p++) { - CASE('~', OnHome()); - default: - break; - } - break; - case '4': - switch (*p++) { - CASE('~', OnEnd()); - default: - break; - } - break; - case '5': - switch (*p++) { - CASE('~', OnPageUp()); - default: - break; - } - break; - case '6': - switch (*p++) { - CASE('~', OnPageDown()); - default: - break; - } - break; - case '7': - switch (*p++) { - CASE('~', OnHome()); - default: - break; - } - break; - case '8': - switch (*p++) { - CASE('~', OnEnd()); - default: - break; - } - break; + CASE('A', OnUpArrow()); /* \e[A is up */ + CASE('B', OnDownArrow()); /* \e[B is down */ + CASE('F', OnEnd()); /* \e[F is end */ + CASE('H', OnHome()); /* \e[H is home */ + CASE('1', OnHome()); /* \e[1~ is home */ + CASE('4', OnEnd()); /* \e[1~ is end */ + CASE('5', OnPageUp()); /* \e[1~ is pgup */ + CASE('6', OnPageDown()); /* \e[1~ is pgdn */ default: break; } @@ -2609,14 +2619,13 @@ static void Tui(void) { SetupDraw(); ScrollOp(&pan.disassembly, GetDisIndex()); if (!(interrupt = setjmp(m->onhalt))) { - for (;;) { + do { if (!(action & FAILURE)) { LoadInstruction(m); 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]; @@ -2642,6 +2651,9 @@ static void Tui(void) { tick = 0; Redraw(); } + if (dialog) { + PrintMessageBox(ttyout, dialog, tyn, txn); + } if (action & FAILURE) { LOGF("TUI FAILURE"); PrintMessageBox(ttyout, systemfailure, tyn, txn); @@ -2651,8 +2663,9 @@ static void Tui(void) { LeaveScreen(); exit(1); } - } else if (!IsExecuting() || (!(action & CONTINUE) && !(action & INT) && - HasPendingKeyboard())) { + } else if (dialog || !IsExecuting() || + (!(action & CONTINUE) && !(action & INT) && + HasPendingKeyboard())) { ReadKeyboard(); } if (action & INT) { @@ -2661,13 +2674,11 @@ static void Tui(void) { if (action & (CONTINUE | NEXT | FINISH)) { action &= ~(CONTINUE | NEXT | FINISH); } else { - tuimode = false; - action |= CONTINUE; + action |= EXIT; break; } } if (action & EXIT) { - LeaveScreen(); LOGF("TUI EXIT"); break; } @@ -2723,7 +2734,7 @@ static void Tui(void) { } } } - } + } while (tuimode); } else { if (OnHalt(interrupt)) { goto KeepGoing; @@ -2794,42 +2805,37 @@ int Emulator(int argc, char *argv[]) { int rc, fd; codepath = argv[optind++]; m->fds.p = xcalloc((m->fds.n = 8), sizeof(struct MachineFd)); -Restart: - action = 0; - LoadProgram(m, codepath, argv + optind, environ, elf); - AddHostFd(STDIN_FILENO); - AddHostFd(STDOUT_FILENO); - AddHostFd(STDERR_FILENO); - if (tuimode) { - ttyin = isatty(STDIN_FILENO) ? STDIN_FILENO : OpenDevTty(); - ttyout = isatty(STDOUT_FILENO) ? STDOUT_FILENO : OpenDevTty(); - } else { - ttyin = -1; - ttyout = -1; - } - if (ttyout != -1) { - atexit(TtyRestore1); - xsigaction(SIGWINCH, OnSigWinch, 0, 0, 0); - tyn = 24; - txn = 80; - GetTtySize(ttyout); - 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) { - Exec(); + do { + action = 0; + LoadProgram(m, codepath, argv + optind, environ, elf); + AddHostFd(0); + AddHostFd(1); + AddHostFd(2); + if (tuimode) { + ttyin = isatty(0) ? 0 : OpenDevTty(); + ttyout = isatty(1) ? 1 : OpenDevTty(); } else { - Tui(); + ttyin = -1; + ttyout = -1; } - if (action & RESTART) { - goto Restart; + if (ttyout != -1) { + atexit(TtyRestore1); + xsigaction(SIGWINCH, OnSigWinch, 0, 0, 0); + tyn = 24; + txn = 80; + GetTtySize(ttyout); + if (isatty(0)) m->fds.p[0].cb = &kMachineFdCbPty; + if (isatty(1)) m->fds.p[1].cb = &kMachineFdCbPty; + if (isatty(2)) m->fds.p[2].cb = &kMachineFdCbPty; } - } - if (tuimode) { - LeaveScreen(); - } + do { + if (!tuimode) { + Exec(); + } else { + Tui(); + } + } while (!(action & (RESTART | EXIT))); + } while (action & RESTART); if (printstats) { fprintf(stderr, "taken: %,ld\n", taken); fprintf(stderr, "ntaken: %,ld\n", ntaken); diff --git a/tool/build/lib/debug.c b/tool/build/lib/debug.c index 7c65dde96..51bfc2e84 100644 --- a/tool/build/lib/debug.c +++ b/tool/build/lib/debug.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" +#include "libc/elf/elf.h" #include "libc/log/check.h" #include "libc/runtime/gc.h" #include "libc/sysv/consts/map.h" @@ -28,13 +29,15 @@ void LoadDebugSymbols(struct Elf *elf) { int fd; + size_t n; void *elfmap; struct stat st; const char *path; - if (elf->ehdr) return; + if (elf->ehdr && GetElfSymbolTable(elf->ehdr, elf->size, &n) && n) return; DCHECK_NOTNULL(elf->prog); + fprintf(stderr, "HI %s\n", elf->prog); if ((fd = open(gc(xstrcat(elf->prog, ".dbg")), O_RDONLY)) != -1 || - (fd = open(elf->prog, O_RDONLY))) { + (fd = open(elf->prog, O_RDONLY)) != -1) { if (fstat(fd, &st) != -1 && (elfmap = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) != MAP_FAILED) { diff --git a/tool/build/lib/diself.c b/tool/build/lib/diself.c index 37ccfd028..03965f0f1 100644 --- a/tool/build/lib/diself.c +++ b/tool/build/lib/diself.c @@ -203,5 +203,5 @@ void DisLoadElf(struct Dis *d, struct Elf *elf) { DisLoadElfLoads(d, elf); DisLoadElfSyms(d, elf); DisSortSyms(d); - DisCanonizeSyms(d); + /* DisCanonizeSyms(d); */ } diff --git a/tool/build/lib/lines.c b/tool/build/lib/lines.c new file mode 100644 index 000000000..da07d3382 --- /dev/null +++ b/tool/build/lib/lines.c @@ -0,0 +1,54 @@ +/*-*- 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 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "libc/str/str.h" +#include "tool/build/lib/lines.h" + +struct Lines *NewLines(void) { + return calloc(1, sizeof(struct Lines)); +} + +void FreeLines(struct Lines *lines) { + size_t i; + for (i = 0; i < lines->n; ++i) { + free(lines->p[i]); + } + free(lines); +} + +void AppendLine(struct Lines *lines, const char *s, size_t n) { + lines->p = realloc(lines->p, ++lines->n * sizeof(*lines->p)); + lines->p[lines->n - 1] = strndup(s, n); +} + +void AppendLines(struct Lines *lines, const char *s) { + const char *p; + for (;;) { + p = strchr(s, '\n'); + if (p) { + AppendLine(lines, s, p - s); + s = p + 1; + } else { + if (*s) { + AppendLine(lines, s, -1); + } + break; + } + } +} diff --git a/tool/build/lib/lines.h b/tool/build/lib/lines.h new file mode 100644 index 000000000..bbd3bc78e --- /dev/null +++ b/tool/build/lib/lines.h @@ -0,0 +1,18 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_LINES_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_LINES_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct Lines { + size_t n; + char **p; +}; + +struct Lines *NewLines(void); +void FreeLines(struct Lines *); +void AppendLine(struct Lines *, const char *, size_t); +void AppendLines(struct Lines *, const char *); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_LINES_H_ */ diff --git a/tool/build/lib/loader.c b/tool/build/lib/loader.c index ed3313bdb..e1d5ddce7 100644 --- a/tool/build/lib/loader.c +++ b/tool/build/lib/loader.c @@ -140,7 +140,7 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, size_t i, mappedsize; DCHECK_NOTNULL(prog); elf->prog = prog; - if ((fd = open(prog, O_RDWR)) == -1 || + if ((fd = open(prog, O_RDONLY)) == -1 || (fstat(fd, &st) == -1 || !st.st_size)) { fputs(prog, stderr); fputs(": not found\n", stderr); diff --git a/tool/build/lib/message.c b/tool/build/lib/message.c index 774984a8a..d32a9e771 100644 --- a/tool/build/lib/message.c +++ b/tool/build/lib/message.c @@ -17,30 +17,51 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/check.h" +#include "libc/macros.h" #include "libc/math.h" #include "libc/mem/mem.h" #include "libc/str/str.h" +#include "libc/unicode/unicode.h" #include "tool/build/lib/buffer.h" +#include "tool/build/lib/lines.h" #include "tool/build/lib/panel.h" +static int GetWidthOfLongestLine(struct Lines *lines) { + int i, w, m; + for (m = i = 0; i < lines->n; ++i) { + w = strwidth(lines->p[i], 0); + m = MAX(m, w); + } + return m; +} + void PrintMessageBox(int fd, const char *msg, long tyn, long txn) { - char buf[1]; struct Buffer b; int i, w, h, x, y; - h = 2 + 1 + 2; - w = 3 + strlen(msg) + 3; + struct Lines *lines; + lines = NewLines(); + AppendLines(lines, msg); + h = 3 + lines->n + 3; + w = 4 + GetWidthOfLongestLine(lines) + 4; x = lrint(txn / 2. - w / 2.); y = lrint(tyn / 2. - h / 2.); memset(&b, 0, sizeof(b)); - AppendFmt(&b, "\e[%d;%dH╔", y++, x); - for (i = 0; i < w - 2; ++i) AppendStr(&b, "═"); - AppendStr(&b, "╗"); - AppendFmt(&b, "\e[%d;%dH║ %-*s ║", y++, x, w - 6, ""); - AppendFmt(&b, "\e[%d;%dH║ %-*s ║", y++, x, w - 6, msg); - AppendFmt(&b, "\e[%d;%dH║ %-*s ║", y++, x, w - 6, ""); - AppendFmt(&b, "\e[%d;%dH╚", y++, x); - for (i = 0; i < w - 2; ++i) AppendStr(&b, "═"); - AppendStr(&b, "╝"); + AppendFmt(&b, "\e[%d;%dH", y++, x); + for (i = 0; i < w; ++i) AppendStr(&b, " "); + AppendFmt(&b, "\e[%d;%dH ╔", y++, x); + for (i = 0; i < w - 4; ++i) AppendStr(&b, "═"); + AppendStr(&b, "╗ "); + AppendFmt(&b, "\e[%d;%dH ║ %-*s ║ ", y++, x, w - 8, ""); + for (i = 0; i < lines->n; ++i) { + AppendFmt(&b, "\e[%d;%dH ║ %-*s ║ ", y++, x, w - 8, lines->p[i]); + } + FreeLines(lines); + AppendFmt(&b, "\e[%d;%dH ║ %-*s ║ ", y++, x, w - 8, ""); + AppendFmt(&b, "\e[%d;%dH ╚", y++, x); + for (i = 0; i < w - 4; ++i) AppendStr(&b, "═"); + AppendStr(&b, "╝ "); + AppendFmt(&b, "\e[%d;%dH", y++, x); + for (i = 0; i < w; ++i) AppendStr(&b, " "); CHECK_NE(-1, WriteBuffer(&b, fd)); free(b.p); }