mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-20 01:20:32 +00:00
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:
parent
fa7b4f5bd1
commit
39bf41f4eb
806 changed files with 77494 additions and 63859 deletions
|
@ -18,6 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/log.h"
|
||||
|
||||
const char *GetAddr2linePath(void) {
|
||||
noasan const char *GetAddr2linePath(void) {
|
||||
return commandvenv("ADDR2LINE", "addr2line");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
bool cancolor(void) {
|
||||
static bool once;
|
||||
static bool result;
|
||||
return 1;
|
||||
if (!once) {
|
||||
result = (!IsWindows() || NtGetVersion() >= kNtVersionWindows10 ||
|
||||
!ischardev(1)) &&
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
58
libc/log/countbranch.h
Normal 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_ */
|
34
libc/log/countbranch_data.S
Normal file
34
libc/log/countbranch_data.S
Normal 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
|
90
libc/log/countbranch_report.c
Normal file
90
libc/log/countbranch_report.c
Normal 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,
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
119
libc/log/libfatal.internal.h
Normal file
119
libc/log/libfatal.internal.h
Normal 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_ */
|
|
@ -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 \
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue