Add x86_64-linux-gnu emulator

I wanted a tiny scriptable meltdown proof way to run userspace programs
and visualize how program execution impacts memory. It helps to explain
how things like Actually Portable Executable works. It can show you how
the GCC generated code is going about manipulating matrices and more. I
didn't feel fully comfortable with Qemu and Bochs because I'm not smart
enough to understand them. I wanted something like gVisor but with much
stronger levels of assurances. I wanted a single binary that'll run, on
all major operating systems with an embedded GPL barrier ZIP filesystem
that is tiny enough to transpile to JavaScript and run in browsers too.

https://justine.storage.googleapis.com/emulator625.mp4
This commit is contained in:
Justine Tunney 2020-08-25 04:23:25 -07:00
parent 467504308a
commit f4f4caab0e
1052 changed files with 65667 additions and 7825 deletions

View file

@ -17,42 +17,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/runtime/mappings.h"
#include "libc/stdio/stdio.h"
STATIC_YOINK("ntoa");
STATIC_YOINK("stoa");
/**
* Displays memory mappings in a way that's readable.
*
* It's readable because (1) map sizes are in bytes bytes with thousand
* separators; (2) output is valid code; (3) memory addresses aren't
* obfuscated; (4) we only need 8 hex digits to display each 64kb
* granular 48-bit NexGen32e pointer; (5) ranges are inclusive; and (6)
* gaps are made apparent.
*/
void showmappings(FILE *f) {
size_t i, bytes, maptally, gaptally;
maptally = 0;
gaptally = 0;
(fprintf)(f, "%s%zu%s\n", "_mm.i == ", _mm.i, ";");
for (i = 0; i < _mm.i; ++i) {
if (i && _mm.p[i].x != _mm.p[i - 1].y + 1) {
bytes = _mm.p[i].x - _mm.p[i - 1].y - 1;
bytes *= FRAMESIZE;
gaptally += bytes;
(fprintf)(f, "%s%,9zu%s\n", "/* ", bytes, " */");
}
bytes = _mm.p[i].y - _mm.p[i].x + 1;
bytes *= FRAMESIZE;
maptally += bytes;
(fprintf)(f, "%s%3u%s0x%08x,0x%08x};%s%,9zu%s\n", "_mm.p[", i, "]=={",
_mm.p[i].x, _mm.p[i].y, " /* ", bytes, " */");
}
(fprintf)(f, "%s%,zu%s%,zu%s\n", "/* ", maptally, " bytes mapped w/ ",
gaptally, " bytes gapped */");
fprintf(f, "\n");
const char *GetAddr2linePath(void) {
return commandvenv("ADDR2LINE", "addr2line");
}

View file

@ -23,6 +23,7 @@
#include "libc/fmt/fmt.h"
#include "libc/log/gdb.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/vendor.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
@ -52,8 +53,8 @@ relegated int(attachdebugger)(intptr_t continuetoaddr) {
struct StackFrame *bp;
char pidstr[11], breakcmd[40];
const char *se, *elf, *gdb, *rewind, *layout;
if (!((gdb = commandv(firstnonnull(getenv("GDB"), "gdb"))) &&
(ttyin = ttyout = open(_PATH_TTY, O_RDWR, 0)) != -1)) {
if (IsGenuineCosmo() || !(gdb = GetGdbPath()) ||
(ttyin = ttyout = open(_PATH_TTY, O_RDWR, 0)) == -1) {
return -1;
}
snprintf(pidstr, sizeof(pidstr), "%u", getpid());

View file

@ -20,6 +20,6 @@
#include "libc/dce.h"
#include "libc/log/log.h"
relegated void backtrace(FILE *f) {
void backtrace(FILE *f) {
showbacktrace(f, __builtin_frame_address(0));
}

View file

@ -19,13 +19,14 @@
*/
#include "libc/alg/alg.h"
#include "libc/alg/bisectcarleft.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
@ -36,7 +37,7 @@
#define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (16 + 1))
static char *formataddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
static char *FormatAddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
char *out, unsigned size, bool symbolic) {
int64_t addend;
const char *name;
@ -54,7 +55,7 @@ static char *formataddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
return out;
}
static int printbacktraceusingsymbols(FILE *f, const struct StackFrame *bp,
static int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
char buf[hasatleast kBacktraceBufSize]) {
size_t gi;
intptr_t addr;
@ -62,17 +63,17 @@ static int printbacktraceusingsymbols(FILE *f, const struct StackFrame *bp,
struct SymbolTable *symbols;
const struct StackFrame *frame;
if ((symbols = getsymboltable())) {
garbage = weaken(__garbage);
garbage = weaken(g_garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) {
addr = frame->addr;
if (addr == weakaddr("__gc")) {
if (addr == weakaddr("CollectGarbage")) {
do {
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
} while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage"));
}
fprintf(f, "%p %p %s\n", frame, addr,
formataddress(f, symbols, addr, buf, kBacktraceBufSize, true));
FormatAddress(f, symbols, addr, buf, kBacktraceBufSize, true));
}
return 0;
} else {
@ -80,7 +81,7 @@ static int printbacktraceusingsymbols(FILE *f, const struct StackFrame *bp,
}
}
static int printbacktraceusingaddr2line(
static int PrintBacktraceUsingAddr2line(
FILE *f, const struct StackFrame *bp,
char buf[hasatleast kBacktraceBufSize],
char *argv[hasatleast kBacktraceMaxFrames]) {
@ -90,10 +91,8 @@ static int printbacktraceusingaddr2line(
int rc, pid, tubes[3];
struct Garbages *garbage;
const struct StackFrame *frame;
const char *addr2line, *debugbin, *p1, *p2, *p3;
if (!(debugbin = finddebugbinary()) ||
!(addr2line = emptytonull(firstnonnull(
getenv("ADDR2LINE"), firstnonnull(commandv("addr2line"), ""))))) {
const char *debugbin, *p1, *p2, *p3, *addr2line;
if (!(debugbin = finddebugbinary()) || !(addr2line = GetAddr2linePath())) {
return -1;
}
i = 0;
@ -102,14 +101,14 @@ static int printbacktraceusingaddr2line(
argv[i++] = "-a"; /* filter out w/ shell script wrapper for old versions */
argv[i++] = "-pCife";
argv[i++] = debugbin;
garbage = weaken(__garbage);
garbage = weaken(g_garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame && i < kBacktraceMaxFrames - 1; frame = frame->next) {
addr = frame->addr;
if (addr == weakaddr("__gc")) {
if (addr == weakaddr("CollectGarbage")) {
do {
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
} while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage"));
}
argv[i++] = &buf[j];
j += snprintf(&buf[j], 17, "%#x", addr - 1) + 1;
@ -118,7 +117,9 @@ static int printbacktraceusingaddr2line(
tubes[0] = STDIN_FILENO;
tubes[1] = -1;
tubes[2] = STDERR_FILENO;
if ((pid = spawnve(0, tubes, addr2line, argv, environ)) == -1) return -1;
if ((pid = spawnve(0, tubes, addr2line, argv, environ)) == -1) {
return -1;
}
while ((got = read(tubes[1], buf, kBacktraceBufSize)) > 0) {
for (p1 = buf; got;) {
/*
@ -147,15 +148,15 @@ static int printbacktraceusingaddr2line(
return 0;
}
static noinline int printbacktrace(FILE *f, const struct StackFrame *bp,
static noinline int PrintBacktrace(FILE *f, const struct StackFrame *bp,
char *argv[hasatleast kBacktraceMaxFrames],
char buf[hasatleast kBacktraceBufSize]) {
if (!IsTiny()) {
if (printbacktraceusingaddr2line(f, bp, buf, argv) != -1) {
if (PrintBacktraceUsingAddr2line(f, bp, buf, argv) != -1) {
return 0;
}
}
return printbacktraceusingsymbols(f, bp, buf);
return PrintBacktraceUsingSymbols(f, bp, buf);
}
void showbacktrace(FILE *f, const struct StackFrame *bp) {
@ -164,7 +165,7 @@ void showbacktrace(FILE *f, const struct StackFrame *bp) {
char buf[kBacktraceBufSize];
if (!noreentry) {
noreentry = true;
printbacktrace(f, bp, argv, buf);
PrintBacktrace(f, bp, argv, buf);
noreentry = 0;
}
}

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/log/log.h"

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_LOG_CHECK_H_
#define COSMOPOLITAN_LIBC_LOG_CHECK_H_
#include "libc/dce.h"
#include "libc/macros.h"
/**
* @fileoverview Modern assertions, courtesy of Elgoog.
@ -19,12 +20,12 @@ COSMOPOLITAN_C_START_
#define CHECK_NOTNULL(X, ...) __CHK(ne, !=, NULL, "NULL", X, #X, "" __VA_ARGS__)
#define DCHECK(X, ...) __DCHK(eq, ==, true, "true", !!(X), #X, "" __VA_ARGS__)
#define DCHECK_EQ(Y, X, ...) __DCHK(eq, ==, Y, #X, X, #Y, "" __VA_ARGS__)
#define DCHECK_NE(Y, X, ...) __DCHK(ne, !=, Y, #X, X, #Y, "" __VA_ARGS__)
#define DCHECK_LE(Y, X, ...) __DCHK(le, <=, Y, #X, X, #Y, "" __VA_ARGS__)
#define DCHECK_LT(Y, X, ...) __DCHK(lt, <, Y, #X, X, #Y, "" __VA_ARGS__)
#define DCHECK_GE(Y, X, ...) __DCHK(ge, >=, Y, #X, X, #Y, "" __VA_ARGS__)
#define DCHECK_GT(Y, X, ...) __DCHK(gt, >, Y, #X, X, #Y, "" __VA_ARGS__)
#define DCHECK_EQ(Y, X, ...) __DCHK(eq, ==, Y, #Y, X, #X, "" __VA_ARGS__)
#define DCHECK_NE(Y, X, ...) __DCHK(ne, !=, Y, #Y, X, #X, "" __VA_ARGS__)
#define DCHECK_LE(Y, X, ...) __DCHK(le, <=, Y, #Y, X, #X, "" __VA_ARGS__)
#define DCHECK_LT(Y, X, ...) __DCHK(lt, <, Y, #Y, X, #X, "" __VA_ARGS__)
#define DCHECK_GE(Y, X, ...) __DCHK(ge, >=, Y, #Y, X, #X, "" __VA_ARGS__)
#define DCHECK_GT(Y, X, ...) __DCHK(gt, >, Y, #Y, X, #X, "" __VA_ARGS__)
#define DCHECK_NOTNULL(X, ...) \
__DCHK(ne, !=, NULL, "NULL", X, #X, "" __VA_ARGS__)
@ -48,8 +49,8 @@ COSMOPOLITAN_C_START_
#define __CHK(SUFFIX, OP, WANT, WANTSTR, GOT, GOTSTR, ...) \
do { \
autotype(WANT) Want = (WANT); \
autotype(GOT) Got = (GOT); \
autotype(WANT) Want = (WANT); \
if (!(Want OP Got)) { \
if (!NoDebug()) { \
__check_fail(#SUFFIX, #OP, (uint64_t)Want, (WANTSTR), (uint64_t)Got, \
@ -64,9 +65,11 @@ COSMOPOLITAN_C_START_
#ifdef NDEBUG
#define __DCHK(SUFFIX, OP, WANT, WANTSTR, GOT, ...) \
do { \
autotype(WANT) Want = (WANT); \
autotype(GOT) Got = (GOT); \
if (!(Want OP Got)) unreachable; \
autotype(WANT) Want = (WANT); \
if (!(Want OP Got)) { \
unreachable; \
} \
} while (0)
#else
#define __DCHK(SUFFIX, OP, WANT, WANTSTR, GOT, GOTSTR, ...) \

View file

@ -17,14 +17,19 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
STATIC_YOINK("ntoa");
STATIC_YOINK("stoa");
void __check_fail_aligned(unsigned bytes, uint64_t ptr) {
if (!IsTiny()) memsummary(stderr);
fprintf(stderr, "%s%d%s%#p\n", "error: pointer not ", bytes,
"-byte aligned: ", ptr);
fflush(stderr);
if (!IsTiny()) memsummary(fileno(stderr));
(dprintf)(fileno(stderr), "%s%d%s%#p\n", "error: pointer not ", bytes,
"-byte aligned: ", ptr);
die();
}

View file

@ -25,6 +25,7 @@
#include "libc/log/check.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
@ -51,7 +52,7 @@ relegated void __check_fail(const char *suffix, const char *opstr,
"\tCHECK_%s(%s, %s);\n"
"\t\t → %#lx (%s)\n"
"\t\t%s %#lx (%s)\n",
sufbuf, wantstr, gotstr, got, gotstr, opstr, want, wantstr);
sufbuf, wantstr, gotstr, want, wantstr, opstr, got, gotstr);
if (!isempty(fmt)) {
fputc('\t', stderr);
@ -70,7 +71,8 @@ relegated void __check_fail(const char *suffix, const char *opstr,
if (!IsTiny() && lasterr == ENOMEM) {
fprintf(stderr, "\n");
showmappings(stderr);
fflush(stderr);
PrintMemoryIntervals(fileno(stderr), &_mmi);
}
fflush(stderr);

View file

@ -22,6 +22,7 @@
#include "libc/calls/hefty/spawn.h"
#include "libc/fmt/fmt.h"
#include "libc/log/gdb.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
@ -34,9 +35,7 @@ int(gdbexec)(const char *cmd) {
intptr_t continuetoaddr;
const char *se, *elf, *gdb;
char pidstr[11], breakcmd[40];
if (!(gdb = commandv(firstnonnull(getenv("GDB"), "gdb")))) {
return -1;
}
if (!(gdb = GetGdbPath())) return -1;
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
if ((elf = finddebugbinary())) {
se = "-se";

24
libc/log/gdbpath.c Normal file
View file

@ -0,0 +1,24 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/log.h"
const char *GetGdbPath(void) {
return commandvenv("GDB", "gdb");
}

View file

@ -1,17 +1,17 @@
#ifndef COSMOPOLITAN_LIBC_LOG_INTERNAL_H_
#define COSMOPOLITAN_LIBC_LOG_INTERNAL_H_
#include "libc/log/log.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/log/log.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define RED (cancolor() ? "\x1b[30;101m" : "")
#define RED (cancolor() ? "\x1b[30;101m" : "")
#define UNBOLD (cancolor() ? "\x1b[22m" : "")
#define RED2 (cancolor() ? "\x1b[91;1m" : "")
#define BLUE1 (cancolor() ? "\x1b[94;49m" : "")
#define BLUE2 (cancolor() ? "\x1b[34m" : "")
#define RESET (cancolor() ? "\x1b[0m" : "")
#define RED2 (cancolor() ? "\x1b[91;1m" : "")
#define BLUE1 (cancolor() ? "\x1b[94;49m" : "")
#define BLUE2 (cancolor() ? "\x1b[34m" : "")
#define RESET (cancolor() ? "\x1b[0m" : "")
#define SUBTLE (cancolor() ? "\x1b[35m" : "")
enum NtExceptionHandlerActions;
@ -20,7 +20,6 @@ struct NtExceptionPointers;
extern int kCrashSigs[8];
extern struct sigaction g_oldcrashacts[8];
extern const char kCrashSigNames[8][5] aligned(1);
extern const char kGodHatesFlags[12][2] aligned(1);
extern const char kGregNames[17][4] aligned(1);
extern const char kGregOrder[17] aligned(1);

View file

@ -17,8 +17,8 @@
#ifndef LOGGABLELEVEL
#ifndef NDEBUG
#define LOGGABLELEVEL kLogDebug
#elif IsTiny()
#define LOGGABLELEVEL kLogFatal
/* #elif IsTiny() */
/* #define LOGGABLELEVEL kLogInfo */
#else
#define LOGGABLELEVEL kLogInfo
#endif
@ -37,15 +37,16 @@ extern FILE *g_logfile;
void backtrace(FILE *) relegated; /* shows fn backtrace and args */
void perror(const char *) relegated; /* print the last system error */
void die(void) relegated noreturn; /* print backtrace and abort() */
void meminfo(FILE *); /* shows malloc statistics &c. */
void memsummary(FILE *); /* light version of same thing */
void meminfo(int); /* shows malloc statistics &c. */
void memsummary(int); /* light version of same thing */
uint16_t getttycols(uint16_t);
int getttysize(int, struct winsize *) paramsnonnull();
bool cancolor(void) nothrow nocallback;
bool isterminalinarticulate(void) nosideeffect;
char *commandvenv(const char *, const char *) nodiscard;
const char *GetAddr2linePath(void);
const char *GetGdbPath(void);
void showmappings(FILE *);
void showcrashreports(void);
void callexitontermination(struct sigset *);
bool32 IsDebuggerPresent(bool);

View file

@ -17,8 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/log/log.h"
#include "libc/bits/initializer.h"
#include "libc/stdio/stdio.h"
FILE *g_logfile;

View file

@ -17,26 +17,25 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
STATIC_YOINK("ntoa");
STATIC_YOINK("stoa");
static void onmemchunk(void *start, void *end, size_t used_bytes, void *arg) {
FILE *f = arg;
(fprintf)(f, "%p - %p : %08zx / %08lx\n", start, end, used_bytes,
(dprintf)(*(int *)arg, "%p - %p : %08zx / %08lx\n", start, end, used_bytes,
(intptr_t)end - (intptr_t)start);
}
/**
* Prints memory mappings.
*/
void meminfo(FILE *f) {
memsummary(f);
(fprintf)(f, "%*s %*s %*s %*s\n", POINTER_XDIGITS, "start",
void meminfo(int fd) {
memsummary(fd);
(dprintf)(fd, "%*s %*s %*s %*s\n", POINTER_XDIGITS, "start",
POINTER_XDIGITS, "end", 8, "used", 8, "size");
malloc_inspect_all(onmemchunk, f);
malloc_inspect_all(onmemchunk, &fd);
}

View file

@ -17,15 +17,16 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
STATIC_YOINK("ntoa");
void memsummary(FILE *f) {
struct mallinfo mi = mallinfo();
(fprintf)(f,
void memsummary(int fd) {
struct mallinfo mi;
mi = mallinfo();
(dprintf)(fd,
"arena\t\t%,-12zu\t# space allocated from system\n"
"ordblks\t\t%,-12zu\t# number of free chunks\n"
"hblkhd\t\t%,-12zu\t# space in mmapped regions\n"

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/utsname.h"
#include "libc/calls/ucontext.h"
@ -27,10 +28,12 @@
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
STATIC_YOINK("ftoa");
@ -44,20 +47,23 @@ STATIC_YOINK("stoa");
struct siginfo;
aligned(1) const char kGregOrder[17] = {13, 11, 8, 14, 12, 9, 10, 15, 16,
0, 1, 2, 3, 4, 5, 6, 7};
aligned(1) const char kGregOrder[17] = {
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
};
aligned(1) const char kGregNames[17][4] = {
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "RDI",
"RSI", "RBP", "RBX", "RDX", "RAX", "RCX", "RSP", "RIP"};
aligned(1) const char kGodHatesFlags[12][2] = {
"CF", "VF", "PF", "RF", "AF", "KF", "ZF", "SF", "TF", "IF", "DF", "OF"};
"RSI", "RBP", "RBX", "RDX", "RAX", "RCX", "RSP", "RIP",
};
aligned(1) const char kGodHatesFlags[12] = "CVPRAKZSTIDO";
aligned(1) const char kCrashSigNames[8][5] = {"QUIT", "FPE", "ILL", "SEGV",
"TRAP", "ABRT", "BUS"};
int kCrashSigs[8];
struct sigaction g_oldcrashacts[8];
relegated static const char *tinystrsignal(int sig) {
relegated static const char *TinyStrSignal(int sig) {
size_t i;
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
@ -67,10 +73,10 @@ relegated static const char *tinystrsignal(int sig) {
return "???";
}
relegated static void showfunctioncalls(FILE *f, ucontext_t *ctx) {
fputc('\n', f);
relegated static void ShowFunctionCalls(FILE *f, ucontext_t *ctx) {
struct StackFrame *bp;
struct StackFrame goodframe;
fputc('\n', f);
if (ctx && ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
goodframe.addr = ctx->uc_mcontext.rip;
@ -79,20 +85,20 @@ relegated static void showfunctioncalls(FILE *f, ucontext_t *ctx) {
}
}
relegated static void describecpuflags(FILE *f, unsigned efl) {
relegated static void DescribeCpuFlags(FILE *f, unsigned efl) {
size_t i;
for (i = 0; i < ARRAYLEN(kGodHatesFlags); ++i) {
if (efl & 1) {
fputc(' ', f);
fputc(kGodHatesFlags[i][0], f);
fputc(kGodHatesFlags[i][1], f);
fputc(kGodHatesFlags[i], f);
fputc('F', f);
}
efl >>= 1;
}
(fprintf)(f, " %s%d\n", "IOPL", efl & 3);
}
relegated static void showgeneralregisters(FILE *f, ucontext_t *ctx) {
relegated static void ShowGeneralRegisters(FILE *f, ucontext_t *ctx) {
size_t i, j, k;
long double st;
fputc('\n', f);
@ -112,10 +118,10 @@ relegated static void showgeneralregisters(FILE *f, ucontext_t *ctx) {
}
}
fflush(stderr);
describecpuflags(f, ctx->uc_mcontext.gregs[REG_EFL]);
DescribeCpuFlags(f, ctx->uc_mcontext.gregs[REG_EFL]);
}
relegated static void showsseregisters(FILE *f, ucontext_t *ctx) {
relegated static void ShowSseRegisters(FILE *f, ucontext_t *ctx) {
size_t i;
fputc('\n', f);
for (i = 0; i < 8; ++i) {
@ -126,42 +132,42 @@ relegated static void showsseregisters(FILE *f, ucontext_t *ctx) {
}
}
relegated static void showmemorymappings(FILE *f) {
int c;
FILE *f2;
relegated static void ShowMemoryMappings(int outfd) {
ssize_t rc;
int c, infd;
char buf[64];
if (!IsTiny()) {
showmappings(f);
if (IsLinux()) {
if ((f2 = fopen("/proc/self/maps", "r"))) {
while ((c = fgetc(f2)) != -1) {
if (fputc(c, f) == -1) break;
}
PrintMemoryIntervals(outfd, &_mmi);
if ((infd = open("/proc/self/maps", O_RDONLY)) != -1) {
while ((rc = read(infd, buf, sizeof(buf))) > 0) {
write(outfd, buf, rc);
}
fclose(f2);
}
close(infd);
}
}
relegated static void showcrashreport(int err, FILE *f, int sig,
relegated static void ShowCrashReport(int err, FILE *f, int sig,
ucontext_t *ctx) {
struct utsname names;
(fprintf)(f, VEIL("r", "\n%serror%s: Uncaught SIG%s\n %s\n %s\n"), RED2,
RESET, tinystrsignal(sig), getauxval(AT_EXECFN), strerror(err));
RESET, TinyStrSignal(sig), getauxval(AT_EXECFN), strerror(err));
if (uname(&names) != -1) {
(fprintf)(f, VEIL("r", " %s %s %s %s\n"), names.sysname, names.nodename,
names.release, names.version);
}
showfunctioncalls(f, ctx);
ShowFunctionCalls(f, ctx);
if (ctx) {
showgeneralregisters(f, ctx);
showsseregisters(f, ctx);
ShowGeneralRegisters(f, ctx);
ShowSseRegisters(f, ctx);
}
fputc('\n', f);
memsummary(f);
showmemorymappings(f);
fflush(f);
memsummary(fileno(f));
ShowMemoryMappings(fileno(f));
}
relegated static void restoredefaultcrashsignalhandlers(void) {
relegated static void RestoreDefaultCrashSignalHandlers(void) {
size_t i;
sigset_t ss;
sigemptyset(&ss);
@ -200,7 +206,7 @@ relegated void oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
} else if (isterminalinarticulate() || isrunningundermake()) {
gdbpid = -1;
} else {
restoredefaultcrashsignalhandlers();
RestoreDefaultCrashSignalHandlers();
gdbpid =
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
@ -208,7 +214,7 @@ relegated void oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
: 0);
}
if (gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT)) return;
showcrashreport(err, stderr, sig, ctx);
ShowCrashReport(err, stderr, sig, ctx);
quick_exit(128 + sig);
unreachable;
}

View file

@ -24,12 +24,16 @@
#include "libc/dce.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/log/ubsan.h"
#include "libc/macros.h"
#include "libc/nt/signals.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
STATIC_YOINK("die");
STATIC_YOINK("__ubsan_abort");
extern const unsigned char kOncrashThunks[7][11];
/**
@ -49,11 +53,9 @@ extern const unsigned char kOncrashThunks[7][11];
*
* @see callexitontermination()
*/
optimizesize void showcrashreports(void) {
void showcrashreports(void) {
size_t i;
struct sigaction sa;
if (IsModeDbg()) STATIC_YOINK("__ubsan_abort");
if (!NoDebug()) STATIC_YOINK("die");
/* <SYNC-LIST>: oncrashthunks.S */
kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */
kCrashSigs[1] = SIGFPE; /* 1 / 0 */

View file

@ -25,6 +25,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/math.h"
#include "libc/nexgen32e/nexgen32e.h"
@ -75,6 +76,7 @@ void vflogf_onfail(FILE *f) {
void(vflogf)(unsigned level, const char *file, int line, FILE *f,
const char *fmt, va_list va) {
static struct timespec ts;
bool flush;
struct tm tm;
long double t2;
const char *prog;
@ -85,7 +87,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
if (fileno(f) == -1) return;
t2 = nowl();
secs = t2;
nsec = mod1000000000int64(t2 * 1e9L);
nsec = rem1000000000int64(t2 * 1e9L);
if (secs > ts.tv_sec) {
localtime_r(&secs, &tm);
strftime(timebuf, sizeof(timebuf), "%Y%m%dT%H%M%S", &tm);
@ -93,23 +95,28 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
timebufp = timebuf;
zonebufp = zonebuf;
dots = nsec;
flush = true;
} else {
timebufp = "---------------";
zonebufp = "---";
dots = nsec - ts.tv_nsec;
flush = true;
}
ts.tv_sec = secs;
ts.tv_nsec = nsec;
prog = basename(program_invocation_name);
if (fprintf(f, "%c%s%s%06ld:%s:%d:%.*s:%d] ", loglevel2char(level), timebufp,
zonebufp, mod1000000int64(div1000int64(dots)), file, line,
zonebufp, rem1000000int64(div1000int64(dots)), file, line,
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
vflogf_onfail(f);
}
(vfprintf)(f, fmt, va);
va_end(va);
fputc('\n', f);
if (flush) fflush(f);
if (level == kLogFatal) {
startfatal(file, line);
fprintf(stderr, "fatal error see logfile\n");
die();
unreachable;
}