mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-04 18:28:30 +00:00
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:
parent
467504308a
commit
f4f4caab0e
1052 changed files with 65667 additions and 7825 deletions
|
@ -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");
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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, ...) \
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
24
libc/log/gdbpath.c
Normal 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");
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue