Initial import

This commit is contained in:
Justine Tunney 2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

95
libc/log/attachdebugger.c Normal file
View file

@ -0,0 +1,95 @@
/*-*- 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/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/fmt/fmt.h"
#include "libc/log/gdb.h"
#include "libc/log/log.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/w.h"
/**
* Launches GDB debugger GUI for current process.
*
* This function abstracts the toilsome details of configuring the best
* possible UX for debugging your app, for varying levels of available
* information, on most of the various platforms.
*
* Before calling this function, consider placing showcrashreports() in
* your main function and calling DebugBreak() wherever you want; it's
* safer. Also note the "GDB" environment variable can be set to empty
* string, as a fail-safe for disabling this behavior.
*
* @param continuetoaddr can be a code address, 0, or -1 for auto
* @return gdb pid if continuing, 0 if detached, or -1 w/ errno
* @note this is called via eponymous spinlock macro wrapper
*/
relegated int(attachdebugger)(intptr_t continuetoaddr) {
int ttyin, ttyout;
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)) {
return -1;
}
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
layout = "layout asm";
if ((elf = finddebugbinary())) {
se = "-se";
if (fileexists(__FILE__)) layout = "layout src";
} else {
se = "-q";
elf = "-q";
}
if (continuetoaddr) {
if (continuetoaddr == -1) {
bp = __builtin_frame_address(0);
continuetoaddr = bp->addr;
}
rewind = "-ex";
snprintf(breakcmd, sizeof(breakcmd), "%s *%#p", "break", continuetoaddr);
} else {
rewind = NULL;
breakcmd[0] = '\0';
}
return spawnve(0, (int[3]){ttyin, ttyout, STDERR_FILENO}, gdb,
(char *const[]){
"gdb", "--tui",
"-p", pidstr,
se, elf,
"-ex", "set osabi GNU/Linux",
"-ex", "set complaints 0",
"-ex", "set confirm off",
"-ex", layout,
"-ex", "layout reg",
"-ex", "set var g_gdbsync = 1",
"-q", rewind,
breakcmd, "-ex",
"c", NULL,
},
environ);
}

25
libc/log/backtrace.c Normal file
View file

@ -0,0 +1,25 @@
/*-*- 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/dce.h"
#include "libc/log/log.h"
relegated void backtrace(FILE *f) {
showbacktrace(f, __builtin_frame_address(0));
}

170
libc/log/backtrace2.c Normal file
View file

@ -0,0 +1,170 @@
/*-*- 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/alg/alg.h"
#include "libc/alg/bisectcarleft.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.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/nexgen32e/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (16 + 1))
static char *formataddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
char *out, unsigned size, bool symbolic) {
int64_t addend;
const char *name;
const struct Symbol *symbol;
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end && symbolic)) {
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base - 1)];
addend = addr - st->addr_base - symbol->addr_rva;
name = &st->name_base[symbol->name_rva];
snprintf(out, size, "%s%c%#x", name, addend >= 0 ? '+' : '-', abs(addend));
} else {
snprintf(out, size, "%p", addr);
}
return out;
}
static int printbacktraceusingsymbols(FILE *f, const struct StackFrame *bp,
char buf[hasatleast kBacktraceBufSize]) {
size_t gi;
intptr_t addr;
struct Garbages *garbage;
struct SymbolTable *symbols;
const struct StackFrame *frame;
if ((symbols = getsymboltable())) {
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) {
addr = frame->addr;
if (addr == weakaddr("__gc")) {
do {
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
}
fprintf(f, "%p %p %s\n", frame, addr,
formataddress(f, symbols, addr, buf, kBacktraceBufSize, true));
}
return 0;
} else {
return -1;
}
}
static int printbacktraceusingaddr2line(
FILE *f, const struct StackFrame *bp,
char buf[hasatleast kBacktraceBufSize],
char *argv[hasatleast kBacktraceMaxFrames]) {
ssize_t got;
intptr_t addr;
size_t i, j, gi;
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"), ""))))) {
return -1;
}
i = 0;
j = 0;
argv[i++] = "addr2line";
argv[i++] = "-a"; /* filter out w/ shell script wrapper for old versions */
argv[i++] = "-pCife";
argv[i++] = debugbin;
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame && i < kBacktraceMaxFrames - 1; frame = frame->next) {
addr = frame->addr;
if (addr == weakaddr("__gc")) {
do {
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
}
argv[i++] = &buf[j];
j += snprintf(&buf[j], 17, "%#x", addr - 1) + 1;
}
argv[i++] = NULL;
tubes[0] = STDIN_FILENO;
tubes[1] = -1;
tubes[2] = STDERR_FILENO;
if ((pid = spawnve(0, tubes, addr2line, argv, environ)) == -1) return -1;
while ((got = read(tubes[1], buf, kBacktraceBufSize)) > 0) {
for (p1 = buf; got;) {
/*
* remove racist output from gnu tooling, that can't be disabled
* otherwise, since it breaks other tools like emacs that aren't
* equipped to ignore it, and what's most problematic is that
* addr2line somehow manages to put the racism onto the one line
* in the backtrace we actually care about.
*/
if ((p2 = memmem(p1, got, " (discriminator ",
strlen(" (discriminator ") - 1)) &&
(p3 = memchr(p2, '\n', got - (p2 - p1)))) {
if (p3 > p2 && p3[-1] == '\r') --p3;
fwrite(p1, 1, p2 - p1, f);
got -= p3 - p1;
p1 += p3 - p1;
} else {
fwrite(p1, 1, got, f);
break;
}
}
}
close(tubes[1]);
if (waitpid(pid, &rc, 0) == -1) return -1;
if (WEXITSTATUS(rc) != 0) return -1;
return 0;
}
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) {
return 0;
}
}
return printbacktraceusingsymbols(f, bp, buf);
}
void showbacktrace(FILE *f, const struct StackFrame *bp) {
static bool noreentry;
char *argv[kBacktraceMaxFrames];
char buf[kBacktraceBufSize];
if (!noreentry) {
noreentry = true;
printbacktrace(f, bp, argv, buf);
noreentry = 0;
}
}

43
libc/log/bisectsymbol.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- 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/alg/bisectcarleft.h"
#include "libc/assert.h"
#include "libc/runtime/symbols.h"
/**
* Finds symbol associated with address.
* @param symbol table pointer (null propagating)
* @return symbol address or NULL if not found
*/
const struct Symbol *bisectsymbol(struct SymbolTable *t,
intptr_t virtual_address,
int64_t *opt_out_addend) {
const struct Symbol *symbol = NULL;
int64_t addend = (intptr_t)virtual_address;
if (t && t->count) {
unsigned key = (unsigned)((intptr_t)virtual_address - t->addr_base - 1);
unsigned i = bisectcarleft((const int32_t(*)[2])t->symbols, t->count, key);
assert(0 <= i && i < t->count);
symbol = &t->symbols[i];
addend = (int64_t)key - (int64_t)symbol->addr_rva;
}
if (opt_out_addend) *opt_out_addend = addend;
return symbol;
}

31
libc/log/bsd.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef COSMOPOLITAN_LIBC_LOG_BSD_H_
#define COSMOPOLITAN_LIBC_LOG_BSD_H_
#include "libc/fmt/pflink.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § logging » berkeley logger
*/
void err(int, const char *, ...) printfesque(2) noreturn;
void errx(int, const char *, ...) printfesque(2) noreturn;
void verr(int, const char *, va_list) paramsnonnull((3)) noreturn;
void verrx(int, const char *, va_list) paramsnonnull((3)) noreturn;
void vwarn(const char *, va_list) paramsnonnull((2));
void vwarnx(const char *, va_list) paramsnonnull((2));
void warn(const char *, ...) printfesque(1);
void warnx(const char *, ...) printfesque(1);
#define err(EVAL, FMT, ...) (err)(EVAL, PFLINK(FMT), ##__VA_ARGS__)
#define errx(EVAL, FMT, ...) (errx)(EVAL, PFLINK(FMT), ##__VA_ARGS__)
#define verr(EVAL, FMT, VA) (verr)(EVAL, PFLINK(FMT), VA)
#define verrx(EVAL, FMT, VA) (verrx)(EVAL, PFLINK(FMT), VA)
#define vwarn(FMT, VA) (vwarn)(PFLINK(FMT), VA)
#define vwarnx(FMT, VA) (vwarnx)(PFLINK(FMT), VA)
#define warn(FMT, ...) (warn)(PFLINK(FMT), ##__VA_ARGS__)
#define warnx(FMT, ...) (warn)(PFLINK(FMT), ##__VA_ARGS__)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_BSD_H_ */

120
libc/log/cancolor.c Normal file
View file

@ -0,0 +1,120 @@
/*-*- 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/calls/internal.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/files.h"
#include "libc/nt/pedef.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
static struct CanColor {
bool once;
bool result;
struct OldNtConsole {
unsigned codepage;
unsigned mode;
int64_t handle;
} oldin, oldout;
} g_cancolor;
static textwindows void restorecmdexe(void) {
if (g_cancolor.oldin.handle) {
SetConsoleCP(g_cancolor.oldin.codepage);
SetConsoleMode(g_cancolor.oldin.handle, g_cancolor.oldin.mode);
}
if (g_cancolor.oldout.handle) {
SetConsoleOutputCP(g_cancolor.oldout.codepage);
SetConsoleMode(g_cancolor.oldout.handle, g_cancolor.oldout.mode);
}
}
/**
* Returns true if ANSI terminal colors are appropriate.
*
* We take an optimistic approach here. We use colors, unless we see the
* environment variable TERM=dumb, which is set by software like Emacs.
* It's a common antipattern to check isatty(STDERR_FILENO), since that
* usually makes colors harder to get than they are to remove:
*
* sed 's/\x1b\[[;[:digit:]]*m//g' <color.txt >uncolor.txt
*
* Ideally, all software should be updated to understand color, since
* it's been formally standardized nearly as long as ASCII. Even old
* MS-DOS supports it (but Windows didn't until Windows 10) yet even
* tools like less may need wrapper scripts, e.g.:
*
* #!/bin/sh
* LESSCHARSET=UTF-8 exec /usr/bin/less -RS "$@"
*
* It's that easy fam.
*/
bool cancolor(void) {
int64_t handle;
const char *term;
if (g_cancolor.once) return g_cancolor.result;
g_cancolor.once = true;
if (IsWindows()) {
if ((int)weakaddr("v_ntsubsystem") == kNtImageSubsystemWindowsCui &&
NtGetVersion() >= kNtVersionWindows10) {
atexit(restorecmdexe);
if (GetFileType((handle = g_fds.p[STDIN_FILENO].handle)) ==
kNtFileTypeChar) {
g_cancolor.result = true;
g_cancolor.oldin.handle = handle;
g_cancolor.oldin.codepage = GetConsoleCP();
SetConsoleCP(kNtCpUtf8);
GetConsoleMode(handle, &g_cancolor.oldin.mode);
SetConsoleMode(handle, g_cancolor.oldin.mode | kNtEnableProcessedInput |
kNtEnableVirtualTerminalInput);
}
if (GetFileType((handle = g_fds.p[STDOUT_FILENO].handle)) ==
kNtFileTypeChar ||
GetFileType((handle = g_fds.p[STDERR_FILENO].handle)) ==
kNtFileTypeChar) {
g_cancolor.result = true;
g_cancolor.oldout.handle = handle;
g_cancolor.oldout.codepage = GetConsoleOutputCP();
SetConsoleOutputCP(kNtCpUtf8);
GetConsoleMode(handle, &g_cancolor.oldout.mode);
SetConsoleMode(handle, g_cancolor.oldout.mode |
kNtEnableProcessedOutput |
kNtEnableVirtualTerminalProcessing);
}
}
}
if (!g_cancolor.result) {
if ((term = getenv("TERM"))) {
/* anything but emacs basically */
g_cancolor.result = strcmp(term, "dumb") != 0;
} else {
/* TODO(jart): Why does Mac bash login shell exec nuke TERM? */
g_cancolor.result = IsXnu();
}
}
return g_cancolor.result;
}

96
libc/log/check.h Normal file
View file

@ -0,0 +1,96 @@
#ifndef COSMOPOLITAN_LIBC_LOG_CHECK_H_
#define COSMOPOLITAN_LIBC_LOG_CHECK_H_
#include "libc/dce.h"
/**
* @fileoverview Modern assertions, courtesy of Elgoog.
*/
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define CHECK(X, ...) __CHK(eq, ==, true, "true", !!(X), #X, "" __VA_ARGS__)
#define CHECK_EQ(Y, X, ...) __CHK(eq, ==, Y, #Y, X, #X, "" __VA_ARGS__)
#define CHECK_NE(Y, X, ...) __CHK(ne, !=, Y, #Y, X, #X, "" __VA_ARGS__)
#define CHECK_LE(Y, X, ...) __CHK(le, <=, Y, #Y, X, #X, "" __VA_ARGS__)
#define CHECK_LT(Y, X, ...) __CHK(lt, <, Y, #Y, X, #X, "" __VA_ARGS__)
#define CHECK_GE(Y, X, ...) __CHK(ge, >=, Y, #Y, X, #X, "" __VA_ARGS__)
#define CHECK_GT(Y, X, ...) __CHK(gt, >, Y, #Y, X, #X, "" __VA_ARGS__)
#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_NOTNULL(X, ...) \
__DCHK(ne, !=, NULL, "NULL", X, #X, "" __VA_ARGS__)
#define CHECK_ALIGNED(BYTES, VAR) \
do { \
if (((uintptr_t)VAR & ((BYTES)-1u))) { \
__check_fail_aligned(BYTES, (uintptr_t)VAR); \
unreachable; \
} \
VAR = (typeof(VAR))__builtin_assume_aligned(VAR, BYTES); \
} while (0)
#define DCHECK_ALIGNED(BYTES, VAR) \
do { \
if (((uintptr_t)VAR & ((BYTES)-1u))) { \
__DCHK_ALIGNED(BYTES, (uintptr_t)VAR); \
unreachable; \
} \
VAR = (typeof(VAR))__builtin_assume_aligned(VAR, BYTES); \
} while (0)
#define __CHK(SUFFIX, OP, WANT, WANTSTR, GOT, GOTSTR, ...) \
do { \
autotype(WANT) Want = (WANT); \
autotype(GOT) Got = (GOT); \
if (!(Want OP Got)) { \
if (!NoDebug()) { \
__check_fail(#SUFFIX, #OP, (uint64_t)Want, (WANTSTR), (uint64_t)Got, \
(GOTSTR), __FILE__, __LINE__, __VA_ARGS__); \
} else { \
__check_fail_##SUFFIX((uint64_t)Want, (uint64_t)Got); \
} \
unreachable; \
} \
} while (0)
#ifdef NDEBUG
#define __DCHK(SUFFIX, OP, WANT, WANTSTR, GOT, ...) \
do { \
autotype(WANT) Want = (WANT); \
autotype(GOT) Got = (GOT); \
if (!(Want OP Got)) unreachable; \
} while (0)
#else
#define __DCHK(SUFFIX, OP, WANT, WANTSTR, GOT, GOTSTR, ...) \
__CHK(SUFFIX, OP, WANT, WANTSTR, GOT, GOTSTR, __VA_ARGS__)
#endif
#ifdef NDEBUG
#define __DCHK_ALIGNED(BYTES, VAR)
#else
#define __DCHK_ALIGNED(BYTES, VAR) __check_fail_aligned(BYTES, VAR)
#endif
void __check_fail(const char *, const char *, uint64_t, const char *, uint64_t,
const char *, const char *, int, const char *,
...) relegated noreturn;
void __check_fail_eq(uint64_t, uint64_t) relegated noreturn;
void __check_fail_ne(uint64_t, uint64_t) relegated noreturn;
void __check_fail_le(uint64_t, uint64_t) relegated noreturn;
void __check_fail_lt(uint64_t, uint64_t) relegated noreturn;
void __check_fail_ge(uint64_t, uint64_t) relegated noreturn;
void __check_fail_gt(uint64_t, uint64_t) relegated noreturn;
void __check_fail_aligned(unsigned, uint64_t) relegated noreturn;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_CHECK_H_ */

30
libc/log/checkaligned.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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/dce.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
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);
die();
}

79
libc/log/checkfail.c Normal file
View file

@ -0,0 +1,79 @@
/*-*- 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/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
/**
* Handles failure of CHECK_xx() macros.
*/
relegated void __check_fail(const char *suffix, const char *opstr,
uint64_t want, const char *wantstr, uint64_t got,
const char *gotstr, const char *file, int line,
const char *fmt, ...) {
size_t i;
va_list va;
char sufbuf[8];
int lasterr = errno;
startfatal(file, line);
if (!memccpy(sufbuf, suffix, '\0', sizeof(sufbuf))) strcpy(sufbuf, "?");
strtoupper(sufbuf);
fprintf(stderr,
"check failed\n"
"\tCHECK_%s(%s, %s);\n"
"\t\t → %#lx (%s)\n"
"\t\t%s %#lx (%s)\n",
sufbuf, wantstr, gotstr, got, gotstr, opstr, want, wantstr);
if (!isempty(fmt)) {
fputc('\t', stderr);
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
fputc('\n', stderr);
}
fprintf(stderr, "\t%s\n\t%s%s%s%s\n", strerror(lasterr), SUBTLE,
getauxval(AT_EXECFN), g_argc > 1 ? " \\" : "", RESET);
for (i = 1; i < g_argc; ++i) {
fprintf(stderr, "\t\t%s%s\n", g_argv[i], i < g_argc - 1 ? " \\" : "");
}
if (!IsTiny() && lasterr == ENOMEM) {
fprintf(stderr, "\n");
showmappings(stderr);
}
fflush(stderr);
die();
unreachable;
}

View file

@ -0,0 +1,42 @@
/*-*- 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/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
/**
* Handles failure of CHECK_xx() macros in -DNDEBUG mode.
*
* This handler (1) makes binaries smaller by not embedding source code;
* and therefore (2) less likely to leak sensitive information. This can
* still print backtraces with function names if the .com.dbg file is in
* the same folder.
*
* @see libc/log/thunks/__check_fail_ndebug.S
*/
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
const char *opchar) {
int lasterr = errno;
startfatal_ndebug();
fprintf(stderr, "%s: %#lx %s %#lx (%s)\n", "check failed", want, opchar, got,
strerror(lasterr));
}

42
libc/log/commandvenv.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- 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/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/ok.h"
/**
* Finds full executable path in overridable way.
*/
nodiscard char *commandvenv(const char *var, const char *cmd) {
const char *exepath;
if ((exepath = getenv(var))) {
if (!isempty(exepath) && access(exepath, X_OK) != -1) {
return exepath;
} else {
return NULL;
}
} else if ((exepath = commandv(cmd))) {
return exepath;
} else {
return NULL;
}
}

43
libc/log/die.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- 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/bits/bits.h"
#include "libc/log/log.h"
#include "libc/runtime/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/exit.h"
/**
* Aborts process after printing details on its current state.
*/
relegated noreturn void die(void) {
static bool once;
if (!once) {
once = true;
if (!IsTiny()) {
g_runstate |= RUNSTATE_BROKEN;
if (IsDebuggerPresent(false)) DebugBreak();
backtrace(stderr);
}
exit(EXIT_FAILURE);
unreachable;
}
abort();
unreachable;
}

27
libc/log/err.c Normal file
View file

@ -0,0 +1,27 @@
/*-*- 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/bsd.h"
noreturn void(err)(int eval, const char *fmt, ...) {
va_list va;
va_start(va, fmt);
(verr)(eval, fmt, va);
va_end(va);
}

27
libc/log/errx.c Normal file
View file

@ -0,0 +1,27 @@
/*-*- 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/bsd.h"
noreturn void(errx)(int eval, const char *fmt, ...) {
va_list va;
va_start(va, fmt);
(verrx)(eval, fmt, va);
va_end(va);
}

32
libc/log/flogf.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- 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"
/**
* Writes formatted message w/ timestamp to log.
* @see vflogf()
*/
void(flogf)(unsigned level, const char *file, int line, FILE *f,
const char *fmt, ...) {
va_list va;
va_start(va, fmt);
(vflogf)(level, file, line, f, fmt, va);
va_end(va);
}

37
libc/log/gdb.h Normal file
View file

@ -0,0 +1,37 @@
#ifndef COSMOPOLITAN_LIBC_LOG_GDB_H_
#define COSMOPOLITAN_LIBC_LOG_GDB_H_
#include "libc/calls/calls.h"
#include "libc/runtime/missioncritical.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/w.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern volatile int g_gdbsync;
int gdbexec(const char *);
int attachdebugger(intptr_t);
#define attachdebugger(CONTINUE_TO_ADDR) /* shorten backtraces */ \
SYNCHRONIZE_DEBUGGER((attachdebugger)(CONTINUE_TO_ADDR))
#define SYNCHRONIZE_DEBUGGER(PID) \
({ \
int Rc, Pid = (PID); \
if (Pid != -1) { \
while ((Rc = WAIT4(Pid, NULL, WNOHANG, NULL)) == 0) { \
if (g_gdbsync) { \
g_gdbsync = 0; \
if (Rc > 0) Pid = 0; \
break; \
} else { \
SCHED_YIELD(); \
} \
} \
} \
Pid; \
})
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_GDB_H_ */

78
libc/log/gdbexec.c Normal file
View file

@ -0,0 +1,78 @@
/*-*- 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/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/fmt/fmt.h"
#include "libc/log/gdb.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
/**
* Attachs GDB temporarilly, to do something like print a variable.
*/
int(gdbexec)(const char *cmd) {
int ttyin, ttyout;
struct StackFrame *bp;
intptr_t continuetoaddr;
const char *se, *elf, *gdb;
char pidstr[11], breakcmd[40];
if (!(gdb = commandv(firstnonnull(getenv("GDB"), "gdb")))) {
return -1;
}
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
if ((elf = finddebugbinary())) {
se = "-se";
} else {
se = "-q";
elf = "-q";
}
bp = __builtin_frame_address(0);
continuetoaddr = bp->addr;
snprintf(breakcmd, sizeof(breakcmd), "%s *%#p", "break", bp->addr);
char *const args[] = {
"gdb",
"--nx",
"--nh",
"-p",
pidstr,
se,
elf,
"-ex",
"set osabi GNU/Linux",
"-ex",
"set complaints 0",
"-ex",
"set confirm off",
"-ex",
"set var g_gdbsync = 1",
"-q",
"-ex",
breakcmd,
"-ex",
cmd,
"-ex",
"quit",
NULL,
};
return SYNCHRONIZE_DEBUGGER(spawnve(0, NULL, gdb, args, environ));
}

22
libc/log/gdbsync.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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/gdb.h"
volatile int g_gdbsync;

32
libc/log/getsymbolname.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- 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/elf/elf.h"
#include "libc/runtime/symbols.h"
/**
* Finds starting address of symbol.
* @param symbol table pointer (null propagating)
* @return name string or null if not found
*/
const char *getsymbolname(struct SymbolTable *t, const struct Symbol *symbol) {
return (t && symbol)
? getelfstring(t->elf, t->elfsize, t->name_base, symbol->name_rva)
: NULL;
}

39
libc/log/getsymboltable.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- 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/calls/calls.h"
#include "libc/runtime/symbols.h"
/**
* Returns debug binary symbol table, as global singleton.
* @return symbol table, or NULL w/ errno on first call
*/
struct SymbolTable *getsymboltable(void) {
static bool once;
static struct SymbolTable *singleton;
const char *debugbin;
if (!once) {
once = true;
if ((debugbin = finddebugbinary()) &&
(singleton = opensymboltable(debugbin))) {
__cxa_atexit(closesymboltable, &singleton, NULL);
}
}
return singleton;
}

40
libc/log/getttycols.c Normal file
View file

@ -0,0 +1,40 @@
/*-*- 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"
#include "libc/calls/calls.h"
#include "libc/calls/termios.h"
#include "libc/sysv/consts/fileno.h"
/**
* Shorthand for getting ws_col from getttysize().
*
* It is recommended that programs err on the side of showing more
* information, if this value can't be obtained with certainty.
*
* @return terminal width or defaultcols on error
*/
uint16_t getttycols(uint16_t defaultcols) {
struct winsize wsize;
if (getttysize(STDIN_FILENO, &wsize) != -1) {
return wsize.ws_col;
} else {
return defaultcols;
}
}

47
libc/log/getttysize.c Normal file
View file

@ -0,0 +1,47 @@
/*-*- 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/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/termios.h"
#include "libc/conv/conv.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/termios.h"
/**
* Returns dimensions of controlling terminal.
*
* It is recommended that programs err on the side of showing more
* information, if this value can't be obtained with certainty.
*
* @param out stores determined dimensions, only on success
* @returns -1 on error or something else on success
*/
int getttysize(int fd, struct winsize *out) {
if (isterminalinarticulate()) {
out->ws_col = strtoimax(firstnonnull(getenv("COLUMNS"), "80"), NULL, 0);
out->ws_row = strtoimax(firstnonnull(getenv("ROWS"), "40"), NULL, 0);
out->ws_xpixel = 0;
out->ws_ypixel = 0;
return 0;
} else {
return ioctl(fd, TIOCGWINSZ, out);
}
}

35
libc/log/internal.h Normal file
View file

@ -0,0 +1,35 @@
#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"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#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 SUBTLE (cancolor() ? "\x1b[35m" : "")
enum NtExceptionHandlerActions;
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);
void startfatal(const char *, int) hidden;
void startfatal_ndebug(void) hidden;
void oncrash(int, struct siginfo *, struct ucontext *) relegated;
enum NtExceptionHandlerActions wincrash$nt(
const struct NtExceptionPointers *) relegated;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_INTERNAL_H_ */

View file

@ -0,0 +1,26 @@
/*-*- 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"
#include "libc/runtime/runtime.h"
/**
* Returns true if current process was spawned by GNU Make.
*/
bool isrunningundermake(void) { return !!getenv("MAKEFLAGS"); }

View file

@ -0,0 +1,30 @@
/*-*- 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/bits/safemacros.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
/**
* Checks if we're probably running inside Emacs.
*/
bool isterminalinarticulate(void) {
return strcmp(nulltoempty(getenv("TERM")), "dumb") == 0;
}

215
libc/log/log.h Normal file
View file

@ -0,0 +1,215 @@
#ifndef COSMOPOLITAN_LIBC_LOG_LOG_H_
#define COSMOPOLITAN_LIBC_LOG_LOG_H_
#include "libc/dce.h"
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § liblog
*/
#define kLogFatal 0u
#define kLogError 1u
#define kLogWarn 2u
#define kLogInfo 3u
#define kLogDebug 4u
/**
* Log level for compile-time DCE.
*/
#ifndef LOGGABLELEVEL
#ifndef NDEBUG
#define LOGGABLELEVEL kLogDebug
#elif IsTiny()
#define LOGGABLELEVEL kLogFatal
#else
#define LOGGABLELEVEL kLogInfo
#endif
#endif
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct sigset;
struct winsize;
struct StackFrame;
typedef struct FILE FILE;
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 */
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;
void showmappings(FILE *);
void showcrashreports(void);
void callexitontermination(struct sigset *);
bool32 IsDebuggerPresent(bool);
bool isrunningundermake(void);
void showbacktrace(FILE *, const struct StackFrame *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § liblog » logging
*/
extern unsigned g_loglevel; /* log level for runtime check */
#define LOGGABLE(LEVEL) \
((!isconstant(LEVEL) || (LEVEL) <= LOGGABLELEVEL) && (LEVEL) <= g_loglevel)
#define LOGF(FMT, ...) \
do { \
if (LOGGABLE(kLogInfo)) { \
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
} \
} while (0)
#define VFLOG(FMT, VA) \
do { \
if (LOGGABLE(kLogInfo)) { \
vflogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, VA); \
} \
} while (0)
#define FLOGF(F, FMT, ...) \
do { \
if (LOGGABLE(kLogInfo)) { \
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
} \
} while (0)
#define VFLOGF(F, FMT, VA) \
do { \
if (LOGGABLE(kLogInfo)) { \
vflogf(kLogInfo, __FILE__, __LINE__, F, FMT, VA); \
} \
} while (0)
#define WARNF(FMT, ...) \
do { \
if (LOGGABLE(kLogWarn)) { \
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
} \
} while (0)
#define VWARNF(FMT, VA) \
do { \
if (LOGGABLE(kLogWarn)) { \
vflogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, VA); \
} \
} while (0)
#define FWARNF(F, FMT, ...) \
do { \
if (LOGGABLE(kLogWarn)) { \
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
} \
} while (0)
#define VFWARNF(F, FMT, VA) \
do { \
if (LOGGABLE(kLogWarn)) { \
vflogf(kLogWarn, __FILE__, __LINE__, F, FMT, VA); \
} \
} while (0)
#define FATALF(FMT, ...) \
do { \
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
unreachable; \
} while (0)
#define VFATALF(FMT, VA) \
do { \
vffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, VA); \
unreachable; \
} while (0)
#define FFATALF(F, FMT, ...) \
do { \
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
unreachable; \
} while (0)
#define VFFATALF(F, FMT, VA) \
do { \
vffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, VA); \
unreachable; \
} while (0)
#define DEBUGF(FMT, ...) \
do { \
if (LOGGABLE(kLogDebug)) { \
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
} \
} while (0)
#define VDEBUGF(FMT, VA) \
do { \
if (LOGGABLE(kLogDebug)) { \
vfdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, VA); \
} \
} while (0)
#define FDEBUGF(F, FMT, ...) \
do { \
if (LOGGABLE(kLogDebug)) { \
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
} \
} while (0)
#define VFDEBUGF(F, FMT, VA) \
do { \
if (LOGGABLE(kLogDebug)) { \
vfdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, VA); \
} \
} while (0)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § liblog » on error resume next
*/
#define LOGIFNEG1(FORM) \
({ \
autotype(FORM) Ax = (FORM); \
if (Ax == (typeof(Ax))(-1) && LOGGABLE(kLogWarn)) { \
__logerrno(__FILE__, __LINE__, #FORM); \
} \
Ax; \
})
#define LOGIFNULL(FORM) \
({ \
autotype(FORM) Ax = (FORM); \
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
__logerrno(__FILE__, __LINE__, #FORM); \
} \
Ax; \
})
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § liblog » implementation details
*/
void __logerrno(const char *, int, const char *) relegated;
#define ARGS unsigned, const char *, int, FILE *, const char *
#define ATTR paramsnonnull((5)) printfesque(5)
#define ATTRV paramsnonnull((5, 6))
void flogf(ARGS, ...) ATTR libcesque;
void vflogf(ARGS, va_list) ATTRV libcesque;
void fdebugf(ARGS, ...) asm("flogf") ATTR relegated libcesque;
void vfdebugf(ARGS, va_list) asm("vflogf") ATTRV relegated libcesque;
void ffatalf(ARGS, ...) asm("flogf") ATTR relegated noreturn libcesque;
void vffatalf(ARGS, va_list) asm("vflogf") ATTRV relegated noreturn libcesque;
#undef ARGS
#undef ATTR
#undef ATTRV
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_LOG_H_ */

86
libc/log/log.mk Normal file
View file

@ -0,0 +1,86 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += LIBC_LOG
LIBC_LOG_ARTIFACTS += LIBC_LOG_A
LIBC_LOG = $(LIBC_LOG_A_DEPS) $(LIBC_LOG_A)
LIBC_LOG_A = o/$(MODE)/libc/log/log.a
LIBC_LOG_A_FILES := \
$(wildcard libc/log/thunks/*) \
$(wildcard libc/log/elf/*) \
$(wildcard libc/log/*)
LIBC_LOG_A_HDRS = $(filter %.h,$(LIBC_LOG_A_FILES))
LIBC_LOG_A_SRCS_C = $(filter %.c,$(LIBC_LOG_A_FILES))
LIBC_LOG_A_SRCS_S = $(filter %.S,$(LIBC_LOG_A_FILES))
LIBC_LOG_A_SRCS = \
$(LIBC_LOG_A_SRCS_C) \
$(LIBC_LOG_A_SRCS_S)
LIBC_LOG_A_OBJS = \
$(LIBC_LOG_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_LOG_A_SRCS_C:%.c=o/$(MODE)/%.o) \
$(LIBC_LOG_A_SRCS_S:%.S=o/$(MODE)/%.o)
LIBC_LOG_A_CHECKS = \
$(LIBC_LOG_A).pkg \
$(LIBC_LOG_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_LOG_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_CONV \
LIBC_ELF \
LIBC_ESCAPE \
LIBC_FMT \
LIBC_TINYMATH \
LIBC_NEXGEN32E \
LIBC_NT_KERNELBASE \
LIBC_RAND \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_NT_NTDLL \
LIBC_UNICODE \
LIBC_SYSV \
LIBC_TIME \
THIRD_PARTY_DLMALLOC
LIBC_LOG_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x))))
$(LIBC_LOG_A): libc/log/ \
$(LIBC_LOG_A).pkg \
$(LIBC_LOG_A_OBJS)
$(LIBC_LOG_A).pkg: \
$(LIBC_LOG_A_OBJS) \
$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/log/die.o \
o/$(MODE)/libc/log/perror.o \
o/$(MODE)/libc/log/ftrace.o \
o/$(MODE)/libc/log/ubsan.o \
o/$(MODE)/libc/log/symbols.o \
o/$(MODE)/libc/log/backtrace.o \
o/$(MODE)/libc/log/oncrash.o \
o/$(MODE)/libc/log/shadowargs.o \
o/$(MODE)/libc/log/thunks/__check_fail_ndebug.o: \
OVERRIDE_COPTS += \
$(NO_MAGIC)
LIBC_LOG_LIBS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)))
LIBC_LOG_SRCS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_SRCS))
LIBC_LOG_HDRS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_HDRS))
LIBC_LOG_BINS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_BINS))
LIBC_LOG_CHECKS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_CHECKS))
LIBC_LOG_OBJS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_OBJS))
LIBC_LOG_TESTS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_TESTS))
$(LIBC_LOG_OBJS): $(BUILD_FILES) libc/log/log.mk
.PHONY: o/$(MODE)/libc/log
o/$(MODE)/libc/log: $(LIBC_LOG_CHECKS)

27
libc/log/logerrno.c Normal file
View file

@ -0,0 +1,27 @@
/*-*- 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/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
void __logerrno(const char *file, int line, const char *form) {
flogf(kLogWarn, file, line, NULL, PFLINK("%s → %s"), form, strerror(errno));
}

26
libc/log/logfile.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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/bits/bits.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
FILE *g_logfile;
INITIALIZER(401, _init_g_logfile, (g_logfile = stderr));

33
libc/log/loglevel.S Normal file
View file

@ -0,0 +1,33 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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"
#include "libc/macros.h"
.yoink __FILE__
.bss
.align 4
g_loglevel:
.long 0
.endobj g_loglevel,globl
.previous
.init.start 200,_init_g_loglevel
movb $kLogInfo,g_loglevel(%rip)
.init.end 200,_init_g_loglevel

31
libc/log/malloc_stats.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "third_party/dlmalloc/dlmalloc.h"
STATIC_YOINK("ntoa");
void malloc_stats(void) {
struct MallocStats res = dlmalloc_stats(gm);
(fprintf)(stderr, "max system bytes = %'10zu\n", res.maxfp);
(fprintf)(stderr, "system bytes = %'10zu\n", res.fp);
(fprintf)(stderr, "in use bytes = %'10zu\n", res.used);
}

39
libc/log/meminfo.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- 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/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,
(intptr_t)end - (intptr_t)start);
}
void meminfo(FILE *f) {
memsummary(f);
(fprintf)(f, "%*s %*s %*s %*s\n", POINTER_XDIGITS, "start",
POINTER_XDIGITS, "end", 8, "used", 8, "size");
malloc_inspect_all(onmemchunk, f);
}

38
libc/log/memsummary.c Normal file
View file

@ -0,0 +1,38 @@
/*-*- 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"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
STATIC_YOINK("ntoa");
void memsummary(FILE *f) {
struct mallinfo mi = mallinfo();
(fprintf)(f,
"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"
"usmblks\t\t%,-12zu\t# maximum total allocated space\n"
"uordblks\t%,-12zu\t# total allocated space\n"
"fordblks\t%,-12zu\t# total free space\n"
"keepcost\t%,-12zu\t# releasable (via malloc_trim) space\n\n",
mi.arena, mi.ordblks, mi.hblkhd, mi.usmblks, mi.uordblks,
mi.fordblks, mi.keepcost);
}

214
libc/log/oncrash.c Normal file
View file

@ -0,0 +1,214 @@
/*-*- 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/calls/sigbits.h"
#include "libc/calls/struct/utsname.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/gdb.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/runtime/internal.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/sig.h"
STATIC_YOINK("ftoa");
STATIC_YOINK("ntoa");
STATIC_YOINK("stoa");
/**
* @fileoverview Abnormal termination handling & GUI debugging.
* @see libc/onkill.c
*/
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 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"};
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) {
size_t i;
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
return kCrashSigNames[i];
}
}
return "???";
}
relegated static void showfunctioncalls(FILE *f, ucontext_t *ctx) {
fputc('\n', f);
struct StackFrame *bp;
struct StackFrame goodframe;
if (ctx && ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
goodframe.addr = ctx->uc_mcontext.rip;
bp = &goodframe;
showbacktrace(f, bp);
}
}
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);
}
efl >>= 1;
}
(fprintf)(f, " %s%d\n", "IOPL", efl & 3);
}
relegated static void showgeneralregisters(FILE *f, ucontext_t *ctx) {
size_t i, j, k;
long double st;
fputc('\n', f);
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
if (j > 0) {
fputc(' ', f);
}
(fprintf)(f, "%-3s %016lx", kGregNames[(unsigned)kGregOrder[i]],
ctx->uc_mcontext.gregs[(unsigned)kGregOrder[i]]);
if (++j == 3) {
j = 0;
memcpy(&st, (char *)&ctx->fpustate.st[k], sizeof(st));
(fprintf)(f, " %s(%zu) %Lf", "ST", k, st);
++k;
fputc('\r', f);
fputc('\n', f);
}
}
fflush(stderr);
describecpuflags(f, ctx->uc_mcontext.gregs[REG_EFL]);
}
relegated static void showsseregisters(FILE *f, ucontext_t *ctx) {
size_t i;
fputc('\n', f);
for (i = 0; i < 8; ++i) {
(fprintf)(f, VEIL("r", "%s%-2zu %016lx%016lx %s%-2d %016lx%016lx\n"), "XMM",
i + 0, ctx->fpustate.xmm[i + 0].u64[0],
ctx->fpustate.xmm[i + 0].u64[1], "XMM", i + 8,
ctx->fpustate.xmm[i + 8].u64[0], ctx->fpustate.xmm[i + 8].u64[1]);
}
}
relegated static void showmemorymappings(FILE *f) {
int c;
FILE *f2;
if (!IsTiny()) {
showmappings(f);
if (IsLinux()) {
if ((f2 = fopen("/proc/self/maps", "r"))) {
while ((c = fgetc(f2)) != -1) {
if (fputc(c, f) == -1) break;
}
}
fclose(f2);
}
}
}
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));
if (uname(&names) != -1) {
(fprintf)(f, VEIL("r", " %s %s %s %s\n"), names.sysname, names.nodename,
names.release, names.version);
}
showfunctioncalls(f, ctx);
if (ctx) {
showgeneralregisters(f, ctx);
showsseregisters(f, ctx);
}
fputc('\n', f);
memsummary(f);
showmemorymappings(f);
}
relegated static void restoredefaultcrashsignalhandlers(void) {
size_t i;
sigset_t ss;
sigemptyset(&ss);
sigprocmask(SIG_SETMASK, &ss, NULL);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[i]) sigaction(kCrashSigs[i], &g_oldcrashacts[i], NULL);
}
}
/**
* Crashes in a developer-friendly human-centric way.
*
* We first try to launch GDB if it's an interactive development
* session. Otherwise we show a really good crash report, sort of like
* Python, that includes filenames and line numbers. Many editors, e.g.
* Emacs, will even recognize its syntax for quick hopping to the
* failing line. That's only possible if the the .com.dbg file is in the
* same folder. If the concomitant debug binary can't be found, we
* simply print addresses which may be cross-referenced using objdump.
*
* This function never returns, except for traps w/ human supervision.
*/
relegated void oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
intptr_t rip;
int gdbpid, err;
static bool once;
err = errno;
g_runstate |= RUNSTATE_BROKEN;
if (once) abort();
once = true;
/* TODO(jart): Needs translation for ucontext_t and possibly siginfo_t. */
if (IsFreebsd() || IsOpenbsd()) ctx = NULL;
rip = ctx ? ctx->uc_mcontext.rip : 0;
if ((gdbpid = IsDebuggerPresent(true))) {
DebugBreak();
} else if (isterminalinarticulate() || isrunningundermake()) {
gdbpid = -1;
} else {
restoredefaultcrashsignalhandlers();
gdbpid =
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
? rip
: 0);
}
if (gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT)) return;
showcrashreport(err, stderr, sig, ctx);
quick_exit(128 + sig);
unreachable;
}

92
libc/log/oncrashthunks.S Normal file
View file

@ -0,0 +1,92 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.yoink __FILE__
/ These function names make it a bit more obvious which signal
/ caused the crash, particularly in the GDB GUI. They're coded
/ into an array to pinch pennies on code size registering them.
kOncrashThunks:
.org 11*0
oncrash_sigquit:
push %rbp
mov %rsp,%rbp
call oncrash
pop %rbp
ret
.endfn oncrash_sigquit,globl
.org 11*1
oncrash_sigfpe:
push %rbp
mov %rsp,%rbp
call oncrash
pop %rbp
ret
.endfn oncrash_sigfpe,globl
.org 11*2
oncrash_sigill:
push %rbp
mov %rsp,%rbp
call oncrash
pop %rbp
ret
.endfn oncrash_sigill,globl
.org 11*3
oncrash_sigsegv:
push %rbp
mov %rsp,%rbp
call oncrash
pop %rbp
ret
.endfn oncrash_sigsegv,globl
.org 11*4
oncrash_sigtrap:
push %rbp
mov %rsp,%rbp
call oncrash
pop %rbp
ret
.endfn oncrash_sigtrap,globl
.org 11*5
oncrash_sigabrt:
push %rbp
mov %rsp,%rbp
call oncrash
pop %rbp
ret
.endfn oncrash_sigabrt,globl
.org 11*6
oncrash_sigbus:
push %rbp
mov %rsp,%rbp
call oncrash
pop %rbp
ret
.endfn oncrash_sigbus,globl
.endobj kOncrashThunks,globl

69
libc/log/onkill.c Normal file
View file

@ -0,0 +1,69 @@
/*-*- 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/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
/**
* @fileoverview Default handlers for normal termination signals.
* @note This gets linked when __cxa_atexit() is linked.
* @see also libc/oncrash.c
*/
struct ucontext;
struct siginfo;
static const int sigs[] = {
SIGHUP, /* hangup aka ctrl_close_event */
SIGINT, /* ctrl+c aka ^C aka ETX aka \003 aka ♥ */
SIGTERM /* kill (default signal) */
};
textexit static void __onkill(int sig, struct siginfo *si,
struct ucontext *context) {
/* https://www.tldp.org/LDP/abs/html/exitcodes.html */
exit(128 + sig);
unreachable;
}
/**
* Installs default handlers for friendly kill signals.
* @see showcrashreports()
*/
void callexitontermination(sigset_t *opt_out_exitsigs) {
struct sigaction sa;
if (opt_out_exitsigs) sigemptyset(opt_out_exitsigs);
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = __onkill;
sa.sa_flags = SA_RESETHAND;
for (unsigned i = 0; i < ARRAYLEN(sigs); ++i) {
if (!sigs[i]) continue;
if (opt_out_exitsigs) sigaddset(opt_out_exitsigs, sigs[i]);
sigaction(sigs[i], &sa, NULL);
}
}

28
libc/log/perror.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
void perror(const char *message) {
fprintf(stderr, "%s%s%s: %s: %m: %s\n", RED2, "error", RESET,
program_invocation_name, message);
}

View file

@ -0,0 +1,58 @@
/*-*- 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"
#include "libc/log/shadowargs.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/symbols.h"
alignas(1) const
char __shadowargs_slotnames[SHADOWARGS_SLOTS][SHADOWARGS_MAXNAME] = {
"func", "%rsp", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9",
};
alignas(64) struct ShadowArgs __shadowargs[SHADOWARGS_COUNT];
unsigned __shadowargs_index;
nocallersavedregisters void __fentry__(uint64_t rdi, uint64_t rsi, uint64_t rdx,
uint64_t rcx, uint64_t r8, uint64_t r9) {
void *addr = __builtin_return_address(0);
intptr_t frame = (intptr_t)__builtin_frame_address(0);
unsigned i = __shadowargs_index;
intptr_t lastframe = (intptr_t)__shadowargs[i].frame;
if (frame < lastframe) {
i--;
i &= SHADOWARGS_COUNT - 1;
} else if (frame > lastframe) {
unsigned j = i;
do {
j++;
j &= SHADOWARGS_COUNT - 1;
} while (frame > (intptr_t)__shadowargs[j].frame && j != i);
i = j;
}
__shadowargs[i].addr = addr;
__shadowargs[i].frame = (void *)frame;
__shadowargs[i].arg1 = rdi;
__shadowargs[i].arg2 = rsi;
__shadowargs[i].arg3 = rdx;
__shadowargs[i].arg4 = rcx;
__shadowargs[i].arg5 = r8;
__shadowargs[i].arg6 = r9;
__shadowargs_index = i;
}

53
libc/log/shadowargs.h Normal file
View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 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
*/
#ifndef COSMOPOLITAN_LIBC_SHADOWARGS_H_
#define COSMOPOLITAN_LIBC_SHADOWARGS_H_
#define SHADOWARGS_COUNT 32
#define SHADOWARGS_SLOTS 8
#define SHADOWARGS_MAXNAME 5
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct ShadowArgs {
union {
unsigned long slots[SHADOWARGS_SLOTS];
struct {
void *addr;
void *frame;
unsigned long arg1;
unsigned long arg2;
unsigned long arg3;
unsigned long arg4;
unsigned long arg5;
unsigned long arg6;
};
};
};
hidden extern unsigned __shadowargs_index;
hidden extern struct ShadowArgs __shadowargs[SHADOWARGS_COUNT];
hidden extern const char __shadowargs_slotnames[SHADOWARGS_SLOTS]
[SHADOWARGS_MAXNAME];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_SHADOWARGS_H_ */

View file

@ -0,0 +1,78 @@
/*-*- 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/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/dce.h"
#include "libc/log/internal.h"
#include "libc/log/log.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"
extern const unsigned char kOncrashThunks[7][11];
/**
* Installs crash signal handlers.
*
* Normally, only functions calling die() will print backtraces. This
* function may be called at program startup to install handlers that
* will display similar information, for most types of crashes.
*
* - Backtraces
* - CPU state printout
* - Automatic debugger attachment
*
* Another trick this function enables, is you can press CTRL+\ to open
* the debugger GUI at any point while the program is running. It can be
* useful, for example, if a program is caught in an infinite loop.
*
* @see callexitontermination()
*/
optimizesize 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 */
kCrashSigs[2] = SIGILL; /* illegal instruction */
kCrashSigs[3] = SIGSEGV; /* bad memory access */
kCrashSigs[4] = SIGTRAP; /* bad system call */
kCrashSigs[5] = SIGABRT; /* abort() called */
kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */
/* </SYNC-LIST>: oncrashthunks.S */
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_RESETHAND;
sigfillset(&sa.sa_mask);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
sigdelset(&sa.sa_mask, kCrashSigs[i]);
}
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[i]) {
sa.sa_sigaction = (sigaction_f)kOncrashThunks[i];
sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]);
}
}
}

58
libc/log/showmappings.c Normal file
View file

@ -0,0 +1,58 @@
/*-*- 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/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");
}

34
libc/log/startfatal.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- 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/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
/**
* Prints initial part of fatal message.
*
* @note this is support code for __check_fail(), __assert_fail(), etc.
* @see startfatal_ndebug()
*/
relegated void startfatal(const char *file, int line) {
fflush(stdout);
fprintf(stderr, "%s%s%s:%s:%d:%s%s: ", RED, "error", BLUE1, file, line,
program_invocation_short_name, RESET);
}

View file

@ -0,0 +1,37 @@
/*-*- 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/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/calls/calls.h"
/**
* Prints initial part of fatal message.
*
* @note this is support code for __check_fail(), __assert_fail(), etc.
* @see startfatal()
*/
relegated void startfatal_ndebug(void) {
fflush(stdout);
fflush(stderr);
stderr->bufmode = _IOFBF;
fprintf(stderr, "%s%s%s:%s%s: ", RED, "error", BLUE1, program_invocation_name,
RESET);
}

View file

@ -0,0 +1,28 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.text.unlikely
.yoink __FILE__
/ Code-size saving thunk for CHECK_EQ() in NDEBUG mode.
__check_fail_eq:
loadstr "==",dx
jmp __check_fail_ndebug
.endfn __check_fail_eq,globl

View file

@ -0,0 +1,28 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.text.unlikely
.yoink __FILE__
/ Code-size saving thunk for CHECK_GE() in NDEBUG mode.
__check_fail_ge:
loadstr ">=",dx
jmp __check_fail_ndebug
.endfn __check_fail_ge,globl

View file

@ -0,0 +1,28 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.text.unlikely
.yoink __FILE__
/ Code-size saving thunk for CHECK_GT() in NDEBUG mode.
__check_fail_gt:
loadstr ">",dx
jmp __check_fail_ndebug
.endfn __check_fail_gt,globl

View file

@ -0,0 +1,28 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.text.unlikely
.yoink __FILE__
/ Code-size saving thunk for CHECK_LE() in NDEBUG mode.
__check_fail_le:
loadstr "<=",dx
jmp __check_fail_ndebug
.endfn __check_fail_le,globl

View file

@ -0,0 +1,28 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.text.unlikely
.yoink __FILE__
/ Code-size saving thunk for CHECK_LT() in NDEBUG mode.
__check_fail_lt:
loadstr "<",dx
jmp __check_fail_ndebug
.endfn __check_fail_lt,globl

View file

@ -0,0 +1,29 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.yoink __FILE__
__check_fail_ndebug:
push %rbp
mov %rsp,%rbp
call ___check_fail_ndebug
pop %rbp
jmp die # fewer elements in backtrace
.endfn __check_fail_ndebug,globl

View file

@ -0,0 +1,28 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.text.unlikely
.yoink __FILE__
/ Code-size saving thunk for CHECK_NE() in NDEBUG mode.
__check_fail_ne:
loadstr "!=",dx
jmp __check_fail_ndebug
.endfn __check_fail_ne,globl

122
libc/log/ubsan.c Normal file
View file

@ -0,0 +1,122 @@
/*-*- 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/bits/pushpop.h"
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/log/ubsan.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
static char __ubsan_buf[256];
static const char kUbsanTypeCheckKinds[] = "load of\0"
"store to\0"
"reference binding to\0"
"member access within\0"
"member call on\0"
"constructor call on\0"
"downcast of\0"
"downcast of\0"
"upcast of\0"
"cast to virtual base of\0"
"\0";
void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) {
static bool once;
if (!once) {
once = true;
} else {
abort();
}
g_runstate |= RUNSTATE_BROKEN;
if (IsDebuggerPresent(false)) DebugBreak();
startfatal(loc->file, loc->line);
fprintf(stderr, "%s\n", description);
die();
unreachable;
}
void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info,
uintptr_t index) {
snprintf(__ubsan_buf, sizeof(__ubsan_buf),
"%s index %,lu into %s out of bounds", info->index_type->name, index,
info->array_type->name);
__ubsan_abort(&info->location, __ubsan_buf);
unreachable;
}
void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *type_mismatch,
uintptr_t pointer) {
struct UbsanSourceLocation *loc = &type_mismatch->location;
const char *description;
const char *kind = indexdoublenulstring(kUbsanTypeCheckKinds,
type_mismatch->type_check_kind);
if (pointer == 0) {
description = "null pointer access";
} else if (type_mismatch->alignment != 0 &&
(pointer & (type_mismatch->alignment - 1))) {
description = __ubsan_buf;
snprintf(__ubsan_buf, sizeof(__ubsan_buf), "%s %s %s @%p %s %d",
"unaligned", kind, type_mismatch->type->name, pointer, "align",
type_mismatch->alignment);
} else {
description = __ubsan_buf;
snprintf(__ubsan_buf, sizeof(__ubsan_buf), "%s\n\t%s %s %p %s %s",
"insufficient size", kind, "address", pointer,
"with insufficient space for object of type",
type_mismatch->type->name);
}
__ubsan_abort(loc, description);
unreachable;
}
void ___ubsan_handle_type_mismatch_v1(
struct UbsanTypeMismatchInfoClang *type_mismatch, uintptr_t pointer) {
struct UbsanTypeMismatchInfo mm;
mm.location = type_mismatch->location;
mm.type = type_mismatch->type;
mm.alignment = 1u << type_mismatch->log_alignment;
mm.type_check_kind = type_mismatch->type_check_kind;
__ubsan_handle_type_mismatch(&mm, pointer);
unreachable;
}
void __ubsan_handle_float_cast_overflow(void *data_raw, void *from_raw) {
struct UbsanFloatCastOverflowData *data =
(struct UbsanFloatCastOverflowData *)data_raw;
#if __GNUC__ + 0 >= 6
__ubsan_abort(&data->location, "float cast overflow");
#else
const struct UbsanSourceLocation kUnknownLocation = {
"<unknown file>",
pushpop(0),
pushpop(0),
};
__ubsan_abort(((void)data, &kUnknownLocation), "float cast overflow");
#endif
unreachable;
}

110
libc/log/ubsan.h Normal file
View file

@ -0,0 +1,110 @@
#ifndef COSMOPOLITAN_LIBC_UBSAN_H_
#define COSMOPOLITAN_LIBC_UBSAN_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § runtime » behavior enforcement
*/
struct UbsanSourceLocation {
const char *file;
uint32_t line;
uint32_t column;
};
struct UbsanTypeDescriptor {
uint16_t kind;
uint16_t info;
char name[];
};
struct UbsanTypeMismatchInfo {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
uintptr_t alignment;
uint8_t type_check_kind;
};
struct UbsanTypeMismatchInfoClang {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
unsigned char log_alignment; /* https://reviews.llvm.org/D28244 */
uint8_t type_check_kind;
};
struct UbsanOutOfBoundsInfo {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *array_type;
struct UbsanTypeDescriptor *index_type;
};
struct UbsanUnreachableData {
struct UbsanSourceLocation location;
};
struct UbsanVlaBoundData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanNonnullArgData {
struct UbsanSourceLocation location;
struct UbsanSourceLocation attr_location;
};
struct UbsanCfiBadIcallData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanNonnullReturnData {
struct UbsanSourceLocation location;
struct UbsanSourceLocation attr_location;
};
struct UbsanFunctionTypeMismatchData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanInvalidValueData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanOverflowData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *type;
};
struct UbsanFloatCastOverflowData {
#if __GNUC__ + 0 >= 6
struct UbsanSourceLocation location;
#endif
struct UbsanTypeDescriptor *from_type;
struct UbsanTypeDescriptor *to_type;
};
struct UbsanOutOfBoundsData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *arraytype;
struct UbsanTypeDescriptor *index_type;
};
struct UbsanShiftOutOfBoundsData {
struct UbsanSourceLocation location;
struct UbsanTypeDescriptor *lhs_type;
struct UbsanTypeDescriptor *rhs_type;
};
void __ubsan_abort(const struct UbsanSourceLocation *,
const char *) relegated hidden noreturn;
void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *,
uintptr_t) relegated hidden noreturn;
void ___ubsan_handle_type_mismatch_v1(struct UbsanTypeMismatchInfoClang *,
uintptr_t) relegated hidden noreturn;
void __ubsan_handle_float_cast_overflow(void *,
void *) relegated hidden noreturn;
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_UBSAN_H_ */

266
libc/log/ubsanjmp.S Normal file
View file

@ -0,0 +1,266 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.h"
.text.unlikely
.yoink __FILE__
__ubsan_default_options:
ret
.endfn __ubsan_default_options
__ubsan_on_report:
ret
.endfn __ubsan_on_report,globl
__ubsan_get_current_report_data:
xor %eax,%eax
ret
.endfn __ubsan_get_current_report_data,globl
__ubsan_handle_type_mismatch_abort:
jmp __ubsan_handle_type_mismatch
.endfn __ubsan_handle_type_mismatch_abort,globl
__ubsan_handle_float_cast_overflow_abort:
jmp __ubsan_handle_float_cast_overflow
.endfn __ubsan_handle_float_cast_overflow_abort,globl
__ubsan_handle_type_mismatch_v1:
__ubsan_handle_type_mismatch_v1_abort:
jmp ___ubsan_handle_type_mismatch_v1
.endfn __ubsan_handle_type_mismatch_v1,globl
.endfn __ubsan_handle_type_mismatch_v1_abort,globl
__ubsan_handle_add_overflow_abort:
nop
/ fallthrough
.endfn __ubsan_handle_add_overflow_abort,globl
__ubsan_handle_add_overflow:
loadstr "add_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_add_overflow,globl
__ubsan_handle_alignment_assumption_abort:
nop
/ fallthrough
.endfn __ubsan_handle_alignment_assumption_abort,globl
__ubsan_handle_alignment_assumption:
loadstr "alignment_assumption",si
jmp __ubsan_hop
.endfn __ubsan_handle_alignment_assumption,globl
__ubsan_handle_builtin_unreachable_abort:
nop
/ fallthrough
.endfn __ubsan_handle_builtin_unreachable_abort,globl
__ubsan_handle_builtin_unreachable:
loadstr "builtin_unreachable",si
jmp __ubsan_hop
.endfn __ubsan_handle_builtin_unreachable,globl
__ubsan_handle_cfi_bad_type_abort:
nop
/ fallthrough
.endfn __ubsan_handle_cfi_bad_type_abort,globl
__ubsan_handle_cfi_bad_type:
loadstr "cfi_bad_type",si
jmp __ubsan_hop
.endfn __ubsan_handle_cfi_bad_type,globl
__ubsan_handle_cfi_check_fail_abort:
nop
/ fallthrough
.endfn __ubsan_handle_cfi_check_fail_abort,globl
__ubsan_handle_cfi_check_fail:
loadstr "cfi_check_fail",si
jmp __ubsan_hop
.endfn __ubsan_handle_cfi_check_fail,globl
__ubsan_handle_divrem_overflow_abort:
nop
/ fallthrough
.endfn __ubsan_handle_divrem_overflow_abort,globl
__ubsan_handle_divrem_overflow:
loadstr "divrem_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_divrem_overflow,globl
__ubsan_handle_dynamic_type_cache_miss_abort:
nop
/ fallthrough
.endfn __ubsan_handle_dynamic_type_cache_miss_abort,globl
__ubsan_handle_dynamic_type_cache_miss:
loadstr "dynamic_type_cache_miss",si
jmp __ubsan_hop
.endfn __ubsan_handle_dynamic_type_cache_miss,globl
__ubsan_handle_function_type_mismatch_abort:
nop
/ fallthrough
.endfn __ubsan_handle_function_type_mismatch_abort,globl
__ubsan_handle_function_type_mismatch:
loadstr "function_type_mismatch",si
jmp __ubsan_hop
.endfn __ubsan_handle_function_type_mismatch,globl
__ubsan_handle_implicit_conversion_abort:
nop
/ fallthrough
.endfn __ubsan_handle_implicit_conversion_abort,globl
__ubsan_handle_implicit_conversion:
loadstr "implicit_conversion",si
jmp __ubsan_hop
.endfn __ubsan_handle_implicit_conversion,globl
__ubsan_handle_invalid_builtin_abort:
nop
/ fallthrough
.endfn __ubsan_handle_invalid_builtin_abort,globl
__ubsan_handle_invalid_builtin:
loadstr "invalid_builtin",si
jmp __ubsan_hop
.endfn __ubsan_handle_invalid_builtin,globl
__ubsan_handle_load_invalid_value_abort:
nop
/ fallthrough
.endfn __ubsan_handle_load_invalid_value_abort,globl
__ubsan_handle_load_invalid_value:
loadstr "load_invalid_value (try checking for uninitialized variables)",si
jmp __ubsan_hop
.endfn __ubsan_handle_load_invalid_value,globl
__ubsan_handle_missing_return_abort:
nop
/ fallthrough
.endfn __ubsan_handle_missing_return_abort,globl
__ubsan_handle_missing_return:
loadstr "missing_return",si
jmp __ubsan_hop
.endfn __ubsan_handle_missing_return,globl
__ubsan_handle_mul_overflow_abort:
nop
/ fallthrough
.endfn __ubsan_handle_mul_overflow_abort,globl
__ubsan_handle_mul_overflow:
loadstr "mul_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_mul_overflow,globl
__ubsan_handle_negate_overflow_abort:
nop
/ fallthrough
.endfn __ubsan_handle_negate_overflow_abort,globl
__ubsan_handle_negate_overflow:
loadstr "negate_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_negate_overflow,globl
__ubsan_handle_nonnull_arg_abort:
nop
/ fallthrough
.endfn __ubsan_handle_nonnull_arg_abort,globl
__ubsan_handle_nonnull_arg:
loadstr "nonnull_arg",si
jmp __ubsan_hop
.endfn __ubsan_handle_nonnull_arg,globl
__ubsan_handle_nonnull_return_v1_abort:
nop
/ fallthrough
.endfn __ubsan_handle_nonnull_return_v1_abort,globl
__ubsan_handle_nonnull_return_v1:
loadstr "nonnull_return_v1",si
jmp __ubsan_hop
.endfn __ubsan_handle_nonnull_return_v1,globl
__ubsan_hop:
jmp __ubsan_abort
.endfn __ubsan_hop
__ubsan_handle_nullability_arg_abort:
nop
/ fallthrough
.endfn __ubsan_handle_nullability_arg_abort,globl
__ubsan_handle_nullability_arg:
loadstr "nullability_arg",si
jmp __ubsan_hop
.endfn __ubsan_handle_nullability_arg,globl
__ubsan_handle_nullability_return_v1_abort:
nop
/ fallthrough
.endfn __ubsan_handle_nullability_return_v1_abort,globl
__ubsan_handle_nullability_return_v1:
loadstr "nullability_return_v1",si
jmp __ubsan_hop
.endfn __ubsan_handle_nullability_return_v1,globl
__ubsan_handle_pointer_overflow_abort:
nop
/ fallthrough
.endfn __ubsan_handle_pointer_overflow_abort,globl
__ubsan_handle_pointer_overflow:
loadstr "pointer_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_pointer_overflow,globl
__ubsan_handle_shift_out_of_bounds_abort:
nop
/ fallthrough
.endfn __ubsan_handle_shift_out_of_bounds_abort,globl
__ubsan_handle_shift_out_of_bounds:
loadstr "shift_out_of_bounds",si
jmp __ubsan_hop
.endfn __ubsan_handle_shift_out_of_bounds,globl
__ubsan_handle_sub_overflow_abort:
nop
/ fallthrough
.endfn __ubsan_handle_sub_overflow_abort,globl
__ubsan_handle_sub_overflow:
loadstr "sub_overflow",si
jmp __ubsan_hop
.endfn __ubsan_handle_sub_overflow,globl
__ubsan_handle_vla_bound_not_positive_abort:
nop
/ fallthrough
.endfn __ubsan_handle_vla_bound_not_positive_abort,globl
__ubsan_handle_vla_bound_not_positive:
loadstr "vla_bound_not_positive",si
jmp __ubsan_hop
.endfn __ubsan_handle_vla_bound_not_positive,globl
__ubsan_handle_nonnull_return_abort:
nop
/ fallthrough
.endfn __ubsan_handle_nonnull_return_abort,globl
__ubsan_handle_nonnull_return:
loadstr "nonnull_return",si
jmp __ubsan_hop
.endfn __ubsan_handle_nonnull_return,globl
__ubsan_handle_out_of_bounds_abort:
jmp __ubsan_handle_out_of_bounds
.endfn __ubsan_handle_out_of_bounds_abort,globl
.previous

31
libc/log/verr.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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/bsd.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
noreturn void(verr)(int eval, const char *fmt, va_list va) {
fprintf(stderr, "%s: %s%s%s[%m]: ", program_invocation_name, RED2, "ERROR",
RESET);
if (fmt) (vfprintf)(stderr, fmt, va);
fprintf(stderr, "\n");
exit(eval);
}

31
libc/log/verrx.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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/bsd.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
noreturn void(verrx)(int eval, const char *fmt, va_list va) {
fprintf(stderr, "%s: %s%s%s: ", program_invocation_name, RED2, "ERROR",
RESET);
if (fmt) (vfprintf)(stderr, fmt, va);
fprintf(stderr, "\n");
exit(eval);
}

116
libc/log/vflogf.c Normal file
View file

@ -0,0 +1,116 @@
/*-*- 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/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timeval.h"
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/math.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/time/struct/tm.h"
#include "libc/time/time.h"
#define kNontrivialSize (8 * 1000 * 1000)
static int loglevel2char(unsigned level) {
switch (level) {
case kLogInfo:
return 'I';
case kLogDebug:
return 'D';
case kLogWarn:
return 'W';
case kLogFatal:
return 'F';
default:
return '?';
}
}
/**
* Takes corrective action if logging is on the fritz.
*/
void vflogf_onfail(FILE *f) {
errno_t err;
struct stat st;
if (IsTiny()) return;
err = ferror(f);
if ((err == ENOSPC || err == EDQUOT || err == EFBIG) &&
(fstat(fileno(f), &st) == -1 || st.st_size > kNontrivialSize)) {
ftruncate(fileno(f), 0);
fseek(f, SEEK_SET, 0);
f->beg = f->end = 0;
clearerr(f);
(fprintf)(f, "performed emergency log truncation: %s\n", strerror(err));
}
}
/**
* Writes formatted message w/ timestamp to log.
*/
void(vflogf)(unsigned level, const char *file, int line, FILE *f,
const char *fmt, va_list va) {
static struct timespec ts;
struct tm tm;
long double t2;
const char *prog;
int64_t secs, nsec, dots;
char zonebuf[8], *zonebufp;
char timebuf[24], *timebufp;
if (!f) f = g_logfile;
if (fileno(f) == -1) return;
t2 = nowl();
secs = t2;
nsec = mod1000000000int64(t2 * 1e9L);
if (secs > ts.tv_sec) {
localtime_r(&secs, &tm);
strftime(timebuf, sizeof(timebuf), "%Y%m%dT%H%M%S", &tm);
strftime(zonebuf, sizeof(zonebuf), "%Z", &tm);
timebufp = timebuf;
zonebufp = zonebuf;
dots = nsec;
} else {
timebufp = "---------------";
zonebufp = "---";
dots = nsec - ts.tv_nsec;
}
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,
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
vflogf_onfail(f);
}
(vfprintf)(f, fmt, va);
va_end(va);
fputc('\n', f);
if (level == kLogFatal) {
die();
unreachable;
}
}

30
libc/log/vwarn.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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/bsd.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
void(vwarn)(const char *fmt, va_list va) {
fprintf(stderr, "%s: %s%s%s[%m]: ", program_invocation_name, SUBTLE,
"WARNING", RESET);
if (fmt) (vfprintf)(stderr, fmt, va);
fprintf(stderr, "\n");
}

30
libc/log/vwarnx.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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/bsd.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
void(vwarnx)(const char *fmt, va_list va) {
fprintf(stderr, "%s: %s%s%s: ", program_invocation_name, SUBTLE, "WARNING",
RESET);
if (fmt) (vfprintf)(stderr, fmt, va);
fprintf(stderr, "\n");
}

27
libc/log/warn.c Normal file
View file

@ -0,0 +1,27 @@
/*-*- 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/bsd.h"
void(warn)(const char *fmt, ...) {
va_list va;
va_start(va, fmt);
(vwarn)(fmt, va);
va_end(va);
}

27
libc/log/warnx.c Normal file
View file

@ -0,0 +1,27 @@
/*-*- 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/bsd.h"
void(warnx)(const char *fmt, ...) {
va_list va;
va_start(va, fmt);
(vwarnx)(fmt, va);
va_end(va);
}