Make numerous improvements

- Python static hello world now 1.8mb
- Python static fully loaded now 10mb
- Python HTTPS client now uses MbedTLS
- Python REPL now completes import stmts
- Increase stack size for Python for now
- Begin synthesizing posixpath and ntpath
- Restore Python \N{UNICODE NAME} support
- Restore Python NFKD symbol normalization
- Add optimized code path for Intel SHA-NI
- Get more Python unit tests passing faster
- Get Python help() pagination working on NT
- Python hashlib now supports MbedTLS PBKDF2
- Make memcpy/memmove/memcmp/bcmp/etc. faster
- Add Mersenne Twister and Vigna to LIBC_RAND
- Provide privileged __printf() for error code
- Fix zipos opendir() so that it reports ENOTDIR
- Add basic chmod() implementation for Windows NT
- Add Cosmo's best functions to Python cosmo module
- Pin function trace indent depth to that of caller
- Show memory diagram on invalid access in MODE=dbg
- Differentiate stack overflow on crash in MODE=dbg
- Add stb_truetype and tools for analyzing font files
- Upgrade to UNICODE 13 and reduce its binary footprint
- COMPILE.COM now logs resource usage of build commands
- Start implementing basic poll() support on bare metal
- Set getauxval(AT_EXECFN) to GetModuleFileName() on NT
- Add descriptions to strerror() in non-TINY build modes
- Add COUNTBRANCH() macro to help with micro-optimizations
- Make error / backtrace / asan / memory code more unbreakable
- Add fast perfect C implementation of μ-Law and a-Law audio codecs
- Make strtol() functions consistent with other libc implementations
- Improve Linenoise implementation (see also github.com/jart/bestline)
- COMPILE.COM now suppresses stdout/stderr of successful build commands
This commit is contained in:
Justine Tunney 2021-09-27 22:58:51 -07:00
parent fa7b4f5bd1
commit 39bf41f4eb
806 changed files with 77494 additions and 63859 deletions

View file

@ -18,6 +18,6 @@
*/
#include "libc/log/log.h"
const char *GetAddr2linePath(void) {
noasan const char *GetAddr2linePath(void) {
return commandvenv("ADDR2LINE", "addr2line");
}

View file

@ -17,65 +17,107 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/rusage.h"
#include "libc/fmt/itoa.h"
#include "libc/log/log.h"
#include "libc/math.h"
#include "libc/runtime/clktck.h"
#include "libc/stdio/append.internal.h"
static void AppendInt(char **b, int64_t x) {
char buf[27], *e;
e = FormatInt64Thousands(buf, x);
appendd(b, buf, e - buf);
}
static void AppendMetric(char **b, const char *s1, int64_t x, const char *s2,
const char *nl) {
appends(b, s1);
AppendInt(b, x);
appends(b, s2);
appends(b, nl);
}
static void AppendUnit(char **b, int64_t x, const char *s) {
AppendInt(b, x);
appendw(b, ' ');
appends(b, s);
if (x == 1) {
appendw(b, 's');
}
}
/**
* Generates process resource usage report.
*/
void AppendResourceReport(char **b, struct rusage *ru, const char *nl) {
char ibuf[27];
long utime, stime;
long double ticks;
if (ru->ru_maxrss) {
(appendf)(b, "ballooned to %,ldkb in size%s", ru->ru_maxrss, nl);
AppendMetric(b, "ballooned to ", ru->ru_maxrss, "kb in size", nl);
}
if ((utime = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec) |
(stime = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec)) {
appends(b, "needed ");
AppendInt(b, utime + stime);
appends(b, "us cpu (");
AppendInt(b, (long double)stime / (utime + stime) * 100);
appends(b, "% kernel)");
appends(b, nl);
ticks = ceill((long double)(utime + stime) / (1000000.L / CLK_TCK));
(appendf)(b, "needed %,ldµs cpu (%d%% kernel)%s", utime + stime,
(int)((long double)stime / (utime + stime) * 100), nl);
if (ru->ru_idrss) {
(appendf)(b, "needed %,ldkb memory on average%s",
lroundl(ru->ru_idrss / ticks), nl);
AppendMetric(b, "needed ", lroundl(ru->ru_idrss / ticks),
" memory on average", nl);
}
if (ru->ru_isrss) {
(appendf)(b, "needed %,ldkb stack on average%s",
lroundl(ru->ru_isrss / ticks), nl);
AppendMetric(b, "needed ", lroundl(ru->ru_isrss / ticks),
" stack on average", nl);
}
if (ru->ru_ixrss) {
(appendf)(b, "mapped %,ldkb shared on average%s",
lroundl(ru->ru_ixrss / ticks), nl);
AppendMetric(b, "needed ", lroundl(ru->ru_ixrss / ticks),
" shared on average", nl);
}
}
if (ru->ru_minflt || ru->ru_majflt) {
(appendf)(b, "caused %,ld page faults (%d%% memcpy)%s",
ru->ru_minflt + ru->ru_majflt,
(int)((long double)ru->ru_minflt /
(ru->ru_minflt + ru->ru_majflt) * 100),
nl);
appends(b, "caused ");
AppendInt(b, ru->ru_minflt + ru->ru_majflt);
appends(b, " page faults (");
AppendInt(
b, (long double)ru->ru_minflt / (ru->ru_minflt + ru->ru_majflt) * 100);
appends(b, "% memcpy)");
appends(b, nl);
}
if (ru->ru_nvcsw + ru->ru_nivcsw > 1) {
(appendf)(
b, "%,ld context switches (%d%% consensual)%s",
ru->ru_nvcsw + ru->ru_nivcsw,
(int)((long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100),
nl);
AppendInt(b, ru->ru_nvcsw + ru->ru_nivcsw);
appends(b, " context switch (");
AppendInt(b,
(long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100);
appends(b, "% consensual)");
appends(b, nl);
}
if (ru->ru_msgrcv || ru->ru_msgsnd) {
(appendf)(b, "received %,ld message%s and sent %,ld%s", ru->ru_msgrcv,
ru->ru_msgrcv == 1 ? "" : "s", ru->ru_msgsnd, nl);
appends(b, "received ");
AppendUnit(b, ru->ru_msgrcv, "message");
appends(b, " and sent ");
AppendInt(b, ru->ru_msgsnd);
appends(b, nl);
}
if (ru->ru_inblock || ru->ru_oublock) {
(appendf)(b, "performed %,ld read%s and %,ld write i/o operations%s",
ru->ru_inblock, ru->ru_inblock == 1 ? "" : "s", ru->ru_oublock,
nl);
appends(b, "performed ");
AppendUnit(b, ru->ru_inblock, "read");
appends(b, " and ");
AppendInt(b, ru->ru_oublock);
appends(b, " write i/o operations");
appends(b, nl);
}
if (ru->ru_nsignals) {
(appendf)(b, "received %,ld signals%s", ru->ru_nsignals, nl);
appends(b, "received ");
AppendUnit(b, ru->ru_nsignals, "signal");
appends(b, nl);
}
if (ru->ru_nswap) {
(appendf)(b, "got swapped %,ld times%s", ru->ru_nswap, nl);
appends(b, "got swapped ");
AppendUnit(b, ru->ru_nswap, "time");
appends(b, nl);
}
}

View file

@ -28,10 +28,12 @@
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
@ -40,7 +42,8 @@
#define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
static noasan int PrintBacktraceUsingAddr2line(int fd,
const struct StackFrame *bp) {
ssize_t got;
intptr_t addr;
size_t i, j, gi;
@ -52,9 +55,8 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
if (IsOpenbsd()) return -1;
if (IsWindows()) return -1;
if (!(debugbin = FindDebugBinary()) || !(addr2line = GetAddr2linePath())) {
return -1;
}
if (!(debugbin = FindDebugBinary())) return -1;
if (!(addr2line = GetAddr2linePath())) return -1;
i = 0;
j = 0;
argv[i++] = "addr2line";
@ -132,11 +134,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
strlen(" (discriminator ") - 1)) &&
(p3 = memchr(p2, '\n', got - (p2 - p1)))) {
if (p3 > p2 && p3[-1] == '\r') --p3;
write(fd, p1, p2 - p1);
__write(p1, p2 - p1);
got -= p3 - p1;
p1 += p3 - p1;
} else {
write(fd, p1, got);
__write(p1, got);
break;
}
}
@ -154,7 +156,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
}
}
static int PrintBacktrace(int fd, const struct StackFrame *bp) {
static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
if (!IsTiny()) {
if (PrintBacktraceUsingAddr2line(fd, bp) != -1) {
return 0;
@ -163,7 +165,7 @@ static int PrintBacktrace(int fd, const struct StackFrame *bp) {
return PrintBacktraceUsingSymbols(fd, bp, GetSymbolTable());
}
void ShowBacktrace(int fd, const struct StackFrame *bp) {
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
static bool noreentry;
++ftrace;
if (!bp) bp = __builtin_frame_address(0);

View file

@ -23,6 +23,7 @@
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/nexgen32e/stackframe.h"
@ -40,52 +41,42 @@
* @param st is open symbol table for current executable
* @return -1 w/ errno if error happened
*/
int PrintBacktraceUsingSymbols(int fd, const struct StackFrame *bp,
struct SymbolTable *st) {
int rc;
char *p;
noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
const struct StackFrame *bp,
struct SymbolTable *st) {
size_t gi;
intptr_t addr;
int64_t addend;
int symbol, addend;
struct Garbages *garbage;
char buf[256], ibuf[21];
const struct Symbol *symbol;
const struct StackFrame *frame;
++ftrace;
if (!bp) bp = __builtin_frame_address(0);
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (rc = 0, frame = bp; frame; frame = frame->next) {
for (frame = bp; frame; frame = frame->next) {
addr = frame->addr;
if (addr == weakaddr("__gc")) {
do {
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
}
p = buf;
p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)frame, ibuf, 48));
*p++ = ' ';
p = mempcpy(p, ibuf, uint64toarray_fixed16(addr, ibuf, 48));
*p++ = ' ';
if (st && st->count &&
((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end)) {
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base - 1)];
p = stpcpy(p, &st->name_base[symbol->name_rva]);
addend = addr - st->addr_base - symbol->addr_rva;
*p++ = addend >= 0 ? '+' : '-';
if (addend) *p++ = '0', *p++ = 'x';
p = mempcpy(p, ibuf, uint64toarray_radix16(ABS(addend), ibuf));
/*
* we subtract one to handle the case of noreturn functions with a
* call instruction at the end, since %rip in such cases will point
* to the start of the next function. generally %rip always points
* to the byte after the instruction. one exception is in case like
* __restore_rt where the kernel creates a stack frame that points
* to the beginning of the function.
*/
if ((symbol = GetSymbol(st, addr - 1)) != -1 ||
(symbol = GetSymbol(st, addr - 0)) != -1) {
addend = addr - st->addr_base;
addend -= st->symbols[symbol].x;
} else {
p = stpcpy(p, "UNKNOWN");
}
*p++ = '\n';
if (write(fd, buf, p - buf) == -1) {
rc = -1;
break;
addend = 0;
}
__printf("%p %p %s%+d\r\n", frame, addr, GetSymbolName(st, symbol), addend);
}
--ftrace;
return rc;
return 0;
}

View file

@ -48,6 +48,7 @@
bool cancolor(void) {
static bool once;
static bool result;
return 1;
if (!once) {
result = (!IsWindows() || NtGetVersion() >= kNtVersionWindows10 ||
!ischardev(1)) &&

View file

@ -16,22 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/fileno.h"
/**
* Handles failure of CHECK_xx() macros.
@ -40,47 +34,67 @@ 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, ...) {
int e;
char *p;
size_t i;
va_list va;
char sufbuf[8];
char hostname[32];
int lasterr = errno;
e = errno;
p = __fatalbuf;
__start_fatal(file, line);
if (!memccpy(sufbuf, suffix, '\0', sizeof(sufbuf))) strcpy(sufbuf, "?");
strtoupper(sufbuf);
strcpy(hostname, "unknown");
__stpcpy(hostname, "unknown");
gethostname(hostname, sizeof(hostname));
(dprintf)(STDERR_FILENO,
"check failed on %s pid %d\n"
"\tCHECK_%s(%s, %s);\n"
"\t\t → %#lx (%s)\n"
"\t\t%s %#lx (%s)\n",
hostname, getpid(), sufbuf, wantstr, gotstr, want, wantstr, opstr,
got, gotstr);
p = __stpcpy(p, "check failed on ");
p = __stpcpy(p, hostname);
p = __stpcpy(p, " pid ");
p = __intcpy(p, __getpid());
p = __stpcpy(p, "\n");
p = __stpcpy(p, "\tCHECK_");
for (; *suffix; ++suffix) {
*p++ = *suffix - ('a' <= *suffix && *suffix <= 'z') * 32;
}
p = __stpcpy(p, "(");
p = __stpcpy(p, wantstr);
p = __stpcpy(p, ", ");
p = __stpcpy(p, gotstr);
p = __stpcpy(p, ");\n\t\t → 0x");
p = __hexcpy(p, want);
p = __stpcpy(p, " (");
p = __stpcpy(p, wantstr);
p = __stpcpy(p, ")\n\t\t");
p = __stpcpy(p, opstr);
p = __stpcpy(p, " 0x");
p = __hexcpy(p, got);
p = __stpcpy(p, " (");
p = __stpcpy(p, gotstr);
p = __stpcpy(p, ")\n");
if (!isempty(fmt)) {
(dprintf)(STDERR_FILENO, "\t");
*p++ = '\t';
va_start(va, fmt);
(vdprintf)(STDERR_FILENO, fmt, va);
p += (vsprintf)(p, fmt, va);
va_end(va);
(dprintf)(STDERR_FILENO, "\n");
*p++ = '\n';
}
(dprintf)(STDERR_FILENO, "\t%s\n\t%s%s%s%s\n", strerror(lasterr), SUBTLE,
program_invocation_name, __argc > 1 ? " \\" : "", RESET);
p = __stpcpy(p, "\t");
p = __stpcpy(p, strerror(e));
p = __stpcpy(p, "\n\t");
p = __stpcpy(p, SUBTLE);
p = __stpcpy(p, program_invocation_name);
if (__argc > 1) p = __stpcpy(p, " \\");
p = __stpcpy(p, RESET);
p = __stpcpy(p, "\n");
__write(__fatalbuf, p - __fatalbuf);
for (i = 1; i < __argc; ++i) {
(dprintf)(STDERR_FILENO, "\t\t%s%s\n", __argv[i],
i < __argc - 1 ? " \\" : "");
p = __fatalbuf;
p = __stpcpy(p, "\t\t");
p = __stpcpy(p, __argv[i]);
if (i < __argc - 1) p = __stpcpy(p, " \\");
p = __stpcpy(p, "\n");
}
if (!IsTiny() && lasterr == ENOMEM) {
(dprintf)(STDERR_FILENO, "\n");
PrintMemoryIntervals(STDERR_FILENO, &_mmi);
if (!IsTiny() && e == ENOMEM) {
__write("\n", 1);
PrintMemoryIntervals(2, &_mmi);
}
__die();
unreachable;
}

View file

@ -45,7 +45,7 @@
* or the environment variable was empty; noting that the caller
* should copy this string before saving it
*/
const char *commandvenv(const char *var, const char *cmd) {
noasan const char *commandvenv(const char *var, const char *cmd) {
const char *exepath;
static char pathbuf[PATH_MAX];
if (*cmd == '/' || *cmd == '\\') return cmd;

58
libc/log/countbranch.h Normal file
View file

@ -0,0 +1,58 @@
#ifndef COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_
#define COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#include "libc/macros.internal.h"
#define COUNTBRANCH(x) COUNTBRANCH_(x, #x, STRINGIFY(__FILE__), __LINE__)
#define COUNTBRANCH_(x, xs, file, line) \
COUNTBRANCH__(x, STRINGIFY(xs), STRINGIFY(#x), file, line)
#define COUNTBRANCH__(x, xs, xss, file, line) \
({ \
bool Cond; \
struct countbranch *Info; \
asm(".section .rodata.str1.1,\"aMS\",@progbits,1\n\t" \
".align\t1\n" \
"31338:\t" \
".asciz\t" xs "\n" \
"31339:\t" \
".asciz\t" xss "\n" \
"31340:\t" \
".asciz\t" file "\n\t" \
".previous\n\t" \
".section .yoink\n\t" \
"nopl\tcountbranch_data(%%rip)\n\t" \
".previous\n\t" \
".section .sort.data.countbranch.2,\"a\",@progbits\n\t" \
".align\t8\n31337:\t" \
".quad\t0\n\t" \
".quad\t0\n\t" \
".quad\t31338b\n\t" \
".quad\t31339b\n\t" \
".quad\t31340b\n\t" \
".quad\t" #line "\n\t" \
".previous\n\t" \
"lea\t31337b(%%rip),%0" \
: "=r"(Info)); \
Cond = (x); \
++Info->total; \
if (Cond) ++Info->taken; \
Cond; \
})
struct countbranch {
long total;
long taken;
const char *code;
const char *xcode;
const char *file;
int line;
};
extern struct countbranch countbranch_data[];
void countbranch_report(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_ */

View file

@ -0,0 +1,34 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.yoink countbranch_report
.section .sort.data.countbranch.1,"a",@progbits
.align 8
.globl countbranch_data
countbranch_data:
.previous
.section .sort.data.countbranch.3,"a",@progbits
.align 8
.rept 5
.quad -1
.endr
.previous

View file

@ -0,0 +1,90 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/alg.h"
#include "libc/calls/calls.h"
#include "libc/log/countbranch.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
static double GetTotal(const struct countbranch *p) {
return p->total;
}
static double GetPercent(const struct countbranch *p) {
if (p->total) {
return (double)p->taken / p->total * 100;
} else {
return 50;
}
}
static double RankCounter(const struct countbranch *p) {
double x;
x = GetPercent(p);
x = MIN(x, 100 - x);
return x;
}
static int CompareCounters(const void *a, const void *b) {
double x, y;
x = RankCounter(a);
y = RankCounter(b);
if (x > y) return +1;
if (x < y) return -1;
if (GetTotal(a) < GetTotal(b)) return +1;
if (GetTotal(a) > GetTotal(b)) return -1;
return 0;
}
static size_t CountCounters(void) {
size_t n;
struct countbranch *p;
for (n = 0, p = countbranch_data; p->total >= 0; ++p) ++n;
return n;
}
static void SortCounters(size_t n) {
qsort(countbranch_data, n, sizeof(*countbranch_data), CompareCounters);
}
void countbranch_report(void) {
size_t i, n;
struct countbranch *p;
n = CountCounters();
SortCounters(n);
for (i = n; i--;) {
p = countbranch_data + i;
if (strcmp(p->code, p->xcode)) {
dprintf(2, "%s:%d: %g%% taken (%,ld/%,ld) %s [%s]\n", p->file, p->line,
GetPercent(p), p->taken, p->total, p->code, p->xcode);
} else {
dprintf(2, "%s:%d: %g%% taken (%,ld/%,ld) %s\n", p->file, p->line,
GetPercent(p), p->taken, p->total, p->code);
}
}
}
static textstartup void countbranch_init() {
atexit(countbranch_report);
}
const void *const countbranch_ctor[] initarray = {
countbranch_init,
};

View file

@ -20,6 +20,7 @@
#include "libc/dce.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
/**
@ -33,6 +34,9 @@ relegated wontreturn void __die(void) {
__restore_tty(1);
if (IsDebuggerPresent(false)) DebugBreak();
ShowBacktrace(2, NULL);
exit(77);
} else {
__write_str("PANIC: __DIE() DIED\r\n");
_exit(78);
}
exit(77);
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/bisectcarleft.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/symbols.internal.h"
@ -27,14 +26,6 @@
const char *GetCallerName(const struct StackFrame *bp) {
struct SymbolTable *st;
if (!bp && (bp = __builtin_frame_address(0))) bp = bp->next;
if (bp && (st = GetSymbolTable()) && st->count &&
((intptr_t)bp->addr >= (intptr_t)&_base &&
(intptr_t)bp->addr <= (intptr_t)&_end)) {
return st->name_base +
st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, bp->addr - st->addr_base - 1)]
.name_rva;
} else {
return 0;
}
if (bp) return GetSymbolByAddr(bp->addr - 1);
return 0;
}

View file

@ -34,7 +34,7 @@ static bool IsSiUser(int si_code) {
*/
const char *GetSiCodeName(int sig, int si_code) {
static char b[16];
memset(b, 0, sizeof(b));
bzero(b, sizeof(b));
strcpy(b, "SI_???");
if (si_code == SI_QUEUE) {
strcpy(b + 3, "QUEUE"); /* sent by sigqueue(2) */

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/bisectcarleft.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
@ -25,15 +24,6 @@
* Returns name of symbol at address.
*/
char *GetSymbolByAddr(int64_t addr) {
struct SymbolTable *st;
if ((st = GetSymbolTable()) && st->count &&
((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end)) {
return st->name_base +
st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base)]
.name_rva;
} else {
return 0;
}
struct SymbolTable *st = GetSymbolTable();
return GetSymbolName(st, GetSymbol(st, addr));
}

View file

@ -17,9 +17,11 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
bool IsTerminalInarticulate(void) {
return !strcmp(nulltoempty(getenv("TERM")), "dumb");

View file

@ -0,0 +1,119 @@
#ifndef COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_
#define COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/nr.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern char __fatalbuf[];
forceinline int __getpid(void) {
int rc;
if (!IsWindows()) {
asm volatile("call\t__syscall__"
: "=a"(rc)
: "0"(__NR_getpid)
: "rcx", "r11", "memory");
return rc;
} else {
return GetCurrentProcessId();
}
}
forceinline ssize_t __write(const void *data, size_t size) {
char cf;
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("call\t__syscall__"
: "=@ccc"(cf), "=a"(rc)
: "1"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
if (cf && IsBsd()) rc = -rc;
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
}
}
forceinline size_t __strlen(const char *s) {
size_t i = 0;
while (s[i]) ++i;
return i;
}
forceinline ssize_t __write_str(const char *s) {
return __write(s, __strlen(s));
}
forceinline char *__stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
if (!(d[i] = s[i])) {
return d + i;
}
}
}
forceinline void *__repmovsb(void *di, void *si, size_t cx) {
asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(si), "2"(cx), "m"(*(char(*)[cx])si));
return di;
}
forceinline void *__mempcpy(void *d, const void *s, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
((char *)d)[i] = ((const char *)s)[i];
}
return (char *)d + n;
}
forceinline char *__uintcpy(char p[static 21], uint64_t x) {
char t;
size_t i, a, b;
i = 0;
do {
p[i++] = x % 10 + '0';
x = x / 10;
} while (x > 0);
p[i] = '\0';
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}
forceinline char *__intcpy(char p[static 21], int64_t x) {
if (x < 0) *p++ = '-', x = -(uint64_t)x;
return __uintcpy(p, x);
}
forceinline char *__fixcpy(char p[hasatleast 17], uint64_t x, uint8_t k) {
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
*p = '\0';
return p;
}
forceinline char *__hexcpy(char p[hasatleast 17], uint64_t x) {
return __fixcpy(p, x, ROUNDUP(x ? bsrl(x) + 1 : 1, 4));
}
void __printf(const char *, ...);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_ */

View file

@ -58,6 +58,11 @@ $(LIBC_LOG_A).pkg: \
$(LIBC_LOG_A_OBJS) \
$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/log/backtrace2.o \
o/$(MODE)/libc/log/backtrace3.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all
o/$(MODE)/libc/log/attachdebugger.o \
o/$(MODE)/libc/log/backtrace2.o \
o/$(MODE)/libc/log/backtrace3.o \
@ -65,6 +70,8 @@ o/$(MODE)/libc/log/checkaligned.o \
o/$(MODE)/libc/log/checkfail.o \
o/$(MODE)/libc/log/checkfail_ndebug.o \
o/$(MODE)/libc/log/getsymboltable.o \
o/$(MODE)/libc/log/cancolor.o \
o/$(MODE)/libc/log/restoretty.o \
o/$(MODE)/libc/log/oncrash.o \
o/$(MODE)/libc/log/onkill.o \
o/$(MODE)/libc/log/startfatal.o \

View file

@ -28,13 +28,18 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/color.internal.h"
#include "libc/log/gdb.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/pc.internal.h"
@ -42,6 +47,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/termios.h"
@ -105,11 +111,9 @@ relegated static char *AddFlag(char *p, int b, const char *s) {
return p;
}
relegated static void DescribeCpuFlags(int fd, int flags, int x87sw,
int mxcsr) {
relegated static char *DescribeCpuFlags(char *p, int flags, int x87sw,
int mxcsr) {
unsigned i;
char buf[64], *p;
p = buf;
for (i = 0; i < ARRAYLEN(kCpuFlags); ++i) {
if (flags & 1) {
*p++ = ' ';
@ -130,47 +134,73 @@ relegated static void DescribeCpuFlags(int fd, int flags, int x87sw,
p = AddFlag(p, x87sw & FPU_C1, " C1");
p = AddFlag(p, x87sw & FPU_C2, " C2");
p = AddFlag(p, x87sw & FPU_C3, " C3");
write(fd, buf, p - buf);
return p;
}
relegated static void ShowGeneralRegisters(int fd, ucontext_t *ctx) {
relegated static char *ShowGeneralRegisters(char *p, ucontext_t *ctx) {
int64_t x;
const char *s;
size_t i, j, k;
long double st;
write(fd, "\n", 1);
*p++ = '\n';
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
if (j > 0) write(fd, " ", 1);
dprintf(fd, "%-3s %016lx", kGregNames[(unsigned)kGregOrder[i]],
ctx->uc_mcontext.gregs[(unsigned)kGregOrder[i]]);
if (j > 0) *p++ = ' ';
if (!(s = kGregNames[(unsigned)kGregOrder[i]])[2]) *p++ = ' ';
p = __stpcpy(p, s), *p++ = ' ';
p = __fixcpy(p, ctx->uc_mcontext.gregs[(unsigned)kGregOrder[i]], 64);
if (++j == 3) {
j = 0;
if (ctx->uc_mcontext.fpregs) {
memcpy(&st, (char *)&ctx->uc_mcontext.fpregs->st[k], sizeof(st));
} else {
memset(&st, 0, sizeof(st));
bzero(&st, sizeof(st));
}
dprintf(fd, " %s(%zu) %Lg", "ST", k, st);
++k;
write(fd, "\n", 1);
p = __stpcpy(p, " ST(");
p = __uintcpy(p, k++);
p = __stpcpy(p, ") ");
x = st * 1000;
if (x < 0) x = -x, *p++ = '-';
p = __uintcpy(p, x / 1000), *p++ = '.';
p = __uintcpy(p, x % 1000), *p++ = '\n';
}
}
DescribeCpuFlags(
fd, ctx->uc_mcontext.gregs[REG_EFL],
return DescribeCpuFlags(
p, ctx->uc_mcontext.gregs[REG_EFL],
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0,
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0);
}
relegated static void ShowSseRegisters(int fd, ucontext_t *ctx) {
relegated static char *ShowSseRegisters(char *p, ucontext_t *ctx) {
size_t i;
if (ctx->uc_mcontext.fpregs) {
write(fd, "\n\n", 2);
p = __stpcpy(p, "\n\n");
for (i = 0; i < 8; ++i) {
dprintf(fd, "%s%-2zu %016lx%016lx %s%-2d %016lx%016lx\n", "XMM", i + 0,
ctx->uc_mcontext.fpregs->xmm[i + 0].u64[1],
ctx->uc_mcontext.fpregs->xmm[i + 0].u64[0], "XMM", i + 8,
ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1],
ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0]);
p = __stpcpy(p, "XMM");
if (i >= 10) {
*p++ = i / 10 + '0';
*p++ = i % 10 + '0';
} else {
*p++ = i + '0';
*p++ = ' ';
}
*p++ = ' ';
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 0].u64[1], 64);
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 0].u64[0], 64);
p = __stpcpy(p, " XMM");
if (i + 8 >= 10) {
*p++ = (i + 8) / 10 + '0';
*p++ = (i + 8) % 10 + '0';
} else {
*p++ = (i + 8) + '0';
*p++ = ' ';
}
*p++ = ' ';
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64);
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64);
*p++ = '\n';
}
}
return p;
}
relegated static void ShowMemoryMappings(int outfd) {
@ -181,7 +211,7 @@ relegated static void ShowMemoryMappings(int outfd) {
PrintMemoryIntervals(outfd, &_mmi);
if ((infd = open("/proc/self/maps", O_RDONLY)) != -1) {
while ((rc = read(infd, buf, sizeof(buf))) > 0) {
write(outfd, buf, rc);
__write(buf, rc);
}
}
close(infd);
@ -190,41 +220,70 @@ relegated static void ShowMemoryMappings(int outfd) {
void ShowCrashReportHook(int, int, int, struct siginfo *, ucontext_t *);
relegated static void ShowCrashReport(int err, int fd, int sig,
struct siginfo *si, ucontext_t *ctx) {
relegated void ShowCrashReport(int err, int fd, int sig, struct siginfo *si,
ucontext_t *ctx) {
int i;
char *p;
bool colorful;
char hostname[64];
struct utsname names;
static char buf[4096];
if (weaken(ShowCrashReportHook)) {
ShowCrashReportHook(err, fd, sig, si, ctx);
}
strcpy(hostname, "unknown");
colorful = cancolor();
__stpcpy(hostname, "unknown");
gethostname(hostname, sizeof(hostname));
dprintf(fd,
"\n"
"%serror%s: Uncaught SIG%s (%s) on %s\n"
" %s\n"
" %s\n",
RED2, RESET, TinyStrSignal(sig),
si ? GetSiCodeName(sig, si->si_code) : "???", hostname,
program_invocation_name, strerror(err));
if (uname(&names) != -1) {
dprintf(fd, " %s %s %s %s\n", names.sysname, names.nodename, names.release,
names.version);
p = buf;
p = __stpcpy(p, "\n");
if (colorful) p = __stpcpy(p, "\e[30;101m");
p = __stpcpy(p, "error");
if (colorful) p = __stpcpy(p, "\e[0m");
p = __stpcpy(p, ": Uncaught SIG");
p = __stpcpy(p, TinyStrSignal(sig));
if (si) {
p = __stpcpy(p, " (");
p = __stpcpy(p, GetSiCodeName(sig, si->si_code));
p = __stpcpy(p, ")");
}
p = __stpcpy(p, " on ");
p = __stpcpy(p, hostname);
p = __stpcpy(p, " pid ");
p = __intcpy(p, __getpid());
p = __stpcpy(p, "\n ");
p = __stpcpy(p, program_invocation_name);
p = __stpcpy(p, "\n ");
p = __stpcpy(p, strerror(err));
*p++ = '\n';
if (uname(&names) != -1) {
p = __stpcpy(p, " ");
p = __stpcpy(p, names.sysname), *p++ = ' ';
p = __stpcpy(p, names.nodename), *p++ = ' ';
p = __stpcpy(p, names.release), *p++ = ' ';
p = __stpcpy(p, names.version), *p++ = '\n';
}
__write(buf, p - buf);
ShowFunctionCalls(fd, ctx);
if (ctx) {
ShowGeneralRegisters(fd, ctx);
ShowSseRegisters(fd, ctx);
p = buf;
p = ShowGeneralRegisters(p, ctx);
p = ShowSseRegisters(p, ctx);
*p++ = '\n';
__write(buf, p - buf);
}
write(fd, "\n", 1);
p = buf;
*p++ = '\n';
ShowMemoryMappings(fd);
write(fd, "\n", 1);
for (i = 0; i < __argc; ++i) {
write(fd, __argv[i], strlen(__argv[i]));
write(fd, " ", 1);
__write(buf, p - buf);
if (__argv) {
for (i = 0; i < __argc; ++i) {
if (!__argv[i]) continue;
if (IsAsan() && !__asan_is_valid(__argv[i], 1)) continue;
__write(__argv[i], strlen(__argv[i]));
__write(" ", 1);
}
}
write(fd, "\n", 1);
__write("\n", 1);
}
relegated static void RestoreDefaultCrashSignalHandlers(void) {

View file

@ -56,7 +56,7 @@ textexit static void __onkill(int sig, struct siginfo *si,
void callexitontermination(sigset_t *opt_out_exitsigs) {
struct sigaction sa;
if (opt_out_exitsigs) sigemptyset(opt_out_exitsigs);
memset(&sa, 0, sizeof(sa));
bzero(&sa, sizeof(sa));
sa.sa_sigaction = __onkill;
sa.sa_flags = SA_RESETHAND;
for (unsigned i = 0; i < ARRAYLEN(sigs); ++i) {

View file

@ -18,9 +18,12 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/nt/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/nr.h"
#define RESET_COLOR "\e[0m"
#define SHOW_CURSOR "\e[?25h"
@ -29,6 +32,11 @@
struct termios g_oldtermios;
asm(".section .privileged,\"ax\",@progbits\n__syscall:\n\t"
"syscall\n\t"
"ret\n\t"
".previous");
static textstartup void g_oldtermios_init() {
tcgetattr(1, &g_oldtermios);
}

View file

@ -67,7 +67,7 @@ void ShowCrashReports(void) {
kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */
kCrashSigs[7] = SIGPIPE; /* write to closed thing */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
memset(&sa, 0, sizeof(sa));
bzero(&sa, sizeof(sa));
sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
sigfillset(&sa.sa_mask);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {

View file

@ -16,12 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/fmt/itoa.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
/**
* Prints initial part of fatal message.
@ -35,17 +33,14 @@ relegated void __start_fatal(const char *file, int line) {
__restore_tty(1);
colorful = cancolor();
*p++ = '\r';
if (colorful) p = stpcpy(p, "\e[J\e[30;101m");
p = stpcpy(p, "error");
if (colorful) p = stpcpy(p, "\e[94;49m");
*p++ = ':';
p = stpcpy(p, file);
*p++ = ':';
p += int64toarray_radix10(line, p);
*p++ = ':';
p = stpcpy(p, program_invocation_short_name);
if (colorful) p = stpcpy(p, "\e[0m");
if (colorful) p = __stpcpy(p, "\e[J\e[30;101m");
p = __stpcpy(p, "error");
if (colorful) p = __stpcpy(p, "\e[94;49m"), *p++ = ':';
p = __stpcpy(p, file), *p++ = ':';
p = __intcpy(p, line), *p++ = ':';
p = __stpcpy(p, program_invocation_short_name);
if (colorful) p = __stpcpy(p, "\e[0m");
*p++ = ':';
*p++ = ' ';
write(2, s, p - s);
__write(s, p - s);
}

View file

@ -21,6 +21,11 @@
#include "libc/log/internal.h"
#include "libc/stdio/stdio.h"
asm(".section .privileged,\"ax\",@progbits\n__syscall:\n\t"
"syscall\n\t"
"ret\n\t"
".previous");
/**
* Prints initial part of fatal message.
*