mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-28 07:18:30 +00:00
Make exciting improvements
- Add Lua backtraces to redbean! - Wipe serving keys after redbean forks - Audit redbean to remove free via exit - Log SSL client ciphersuite preferences - Increase ASAN malloc() backtrace depth - Make GetSslRoots() behave as a singleton - Move leaks.c from LIBC_TESTLIB to LIBC_LOG - Add undocumented %n to printf() for newlines - Fix redbean memory leak reindexing inode change - Fix redbean memory leak with Fetch() DNS object - Restore original environ after __cxa_finalize() - Make backtrace always work after __cxa_finalize() - Introduce COUNTEXPR() diagnostic / benchmark tool - Fix a few more instances of errno being clobbered - Consolidate the ANSI color disabling internal APIs
This commit is contained in:
parent
f5831a62fa
commit
af645fcbec
61 changed files with 1354 additions and 814 deletions
|
@ -24,7 +24,11 @@
|
|||
|
||||
/**
|
||||
* Returns directory portion of path.
|
||||
* @param s is mutated
|
||||
*
|
||||
* This returns "." if path doesn't have slashes. If path is empty then
|
||||
* this returns empty string.
|
||||
*
|
||||
* @param s is mutated and must not be NULL
|
||||
*/
|
||||
char *dirname(char *s) {
|
||||
size_t i, n;
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
extern bool __nomultics;
|
||||
|
||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||
|
||||
static void __fmt_free_dtoa(char **mem) {
|
||||
|
@ -385,6 +387,11 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (__nomultics) PUT('\r');
|
||||
PUT('\n');
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
case 'f':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
|
|
|
@ -52,6 +52,10 @@
|
|||
|
||||
STATIC_YOINK("_init_asan");
|
||||
|
||||
#define ASAN_MORGUE_ITEMS 512
|
||||
#define ASAN_MORGUE_THRESHOLD 65536 // morgue memory O(ITEMS*THRESHOLD)
|
||||
#define ASAN_TRACE_ITEMS 16 // backtrace limit on malloc origin
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Address Sanitizer Runtime.
|
||||
*
|
||||
|
@ -83,8 +87,6 @@ STATIC_YOINK("_init_asan");
|
|||
* movq (%addr),%dst
|
||||
*/
|
||||
|
||||
#define ASAN_MORGUE_SIZE 128
|
||||
|
||||
#define HOOK(HOOK, IMPL) \
|
||||
do { \
|
||||
if (weaken(HOOK)) { \
|
||||
|
@ -104,7 +106,7 @@ STATIC_YOINK("_init_asan");
|
|||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
|
||||
struct AsanTrace {
|
||||
intptr_t p[4];
|
||||
uint32_t p[ASAN_TRACE_ITEMS]; // assumes linkage into 32-bit space
|
||||
};
|
||||
|
||||
struct AsanExtra {
|
||||
|
@ -139,7 +141,12 @@ struct AsanGlobal {
|
|||
|
||||
struct AsanMorgue {
|
||||
unsigned i;
|
||||
void *p[ASAN_MORGUE_SIZE];
|
||||
void *p[ASAN_MORGUE_ITEMS];
|
||||
};
|
||||
|
||||
struct ReportOriginHeap {
|
||||
const unsigned char *a;
|
||||
int z;
|
||||
};
|
||||
|
||||
bool __asan_noreentry;
|
||||
|
@ -657,11 +664,6 @@ static void __asan_report_memory_origin_image(intptr_t a, int z) {
|
|||
}
|
||||
}
|
||||
|
||||
struct ReportOriginHeap {
|
||||
const unsigned char *a;
|
||||
int z;
|
||||
};
|
||||
|
||||
static noasan void OnMemory(void *x, void *y, size_t n, void *a) {
|
||||
const unsigned char *p = x;
|
||||
struct ReportOriginHeap *t = a;
|
||||
|
@ -725,6 +727,7 @@ nodiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
|||
uint64_t x, y, z;
|
||||
char *p, *q, *base;
|
||||
struct MemoryIntervals *m;
|
||||
++g_ftrace;
|
||||
p = __fatalbuf;
|
||||
kprintf("%n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p%n%s%n",
|
||||
__asan_describe_access_poison(kind), size, message, addr,
|
||||
|
@ -805,6 +808,7 @@ nodiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
|||
kprintf("%s", __fatalbuf);
|
||||
__asan_report_memory_origin(addr, size, kind);
|
||||
kprintf("%nthe crash was caused by%n");
|
||||
--g_ftrace;
|
||||
return __asan_die();
|
||||
}
|
||||
|
||||
|
@ -1005,7 +1009,7 @@ int __asan_print_trace(void *p) {
|
|||
kprintf(" bad cookie");
|
||||
return -1;
|
||||
}
|
||||
kprintf("%n%p %,lu bytes [asan]", (char *)p + 16, n);
|
||||
kprintf("%n%p %,lu bytes [asan]", (char *)p, n);
|
||||
if (!__asan_is_mapped((((intptr_t)p >> 3) + 0x7fff8000) >> 16)) {
|
||||
kprintf(" (shadow not mapped?!)");
|
||||
}
|
||||
|
@ -1024,7 +1028,7 @@ static void __asan_deallocate(char *p, long kind) {
|
|||
if ((e = __asan_get_extra(p, &c))) {
|
||||
if (__asan_read48(e->size, &n)) {
|
||||
__asan_poison((uintptr_t)p, c, kind);
|
||||
if (c <= FRAMESIZE) {
|
||||
if (c <= ASAN_MORGUE_THRESHOLD) {
|
||||
p = __asan_morgue_add(p);
|
||||
}
|
||||
weaken(dlfree)(p);
|
||||
|
|
|
@ -16,18 +16,19 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
#define ToUpper(c) \
|
||||
(IsWindows() && (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
forceinline int Identity(int c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns value of environment variable, or NULL if not found.
|
||||
*
|
||||
* Environment variables can store empty string on Unix but not Windows.
|
||||
*/
|
||||
char *getenv(const char *s) {
|
||||
forceinline int ToUpper(int c) {
|
||||
return 'a' <= c && c <= 'z' ? c - ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
forceinline char *GetEnv(const char *s, int xlat(int)) {
|
||||
char **p;
|
||||
size_t i, j;
|
||||
if ((p = environ)) {
|
||||
|
@ -39,7 +40,7 @@ char *getenv(const char *s) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
if (ToUpper(s[j]) != ToUpper(p[i][j])) {
|
||||
if (xlat(s[j]) != xlat(p[i][j])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -47,3 +48,21 @@ char *getenv(const char *s) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns value of environment variable, or NULL if not found.
|
||||
*
|
||||
* Environment variables can store empty string on Unix but not Windows.
|
||||
*
|
||||
* @note should not be used after __cxa_finalize() is called
|
||||
*/
|
||||
char *getenv(const char *s) {
|
||||
char *r;
|
||||
if (!IsWindows()) {
|
||||
r = GetEnv(s, Identity);
|
||||
} else {
|
||||
r = GetEnv(s, ToUpper);
|
||||
}
|
||||
SYSDEBUG("getenv(%#s) → %#s", s, r);
|
||||
return r;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,31 +16,17 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/nt/version.h"
|
||||
|
||||
bool g_isterminalinarticulate;
|
||||
|
||||
bool IsTerminalInarticulate(void) {
|
||||
return g_isterminalinarticulate;
|
||||
/**
|
||||
* Returns true if we're running at least Windows 10.
|
||||
*
|
||||
* This function may only be called if IsWindows() is true.
|
||||
*/
|
||||
privileged bool(IsAtLeastWindows10)(void) {
|
||||
assert(IsWindows());
|
||||
return IsAtLeastWindows10();
|
||||
}
|
||||
|
||||
textstartup noasan void g_isterminalinarticulate_init(int argc, char **argv,
|
||||
char **envp,
|
||||
intptr_t *auxv) {
|
||||
char *s;
|
||||
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
||||
g_isterminalinarticulate = true;
|
||||
} else if ((s = __getenv(envp, "TERM"))) {
|
||||
g_isterminalinarticulate = !__strcmp(s, "dumb");
|
||||
}
|
||||
}
|
||||
|
||||
const void *const g_isterminalinarticulate_ctor[] initarray = {
|
||||
g_isterminalinarticulate_init,
|
||||
};
|
|
@ -37,7 +37,7 @@ noasan noubsan int IsDebuggerPresent(bool force) {
|
|||
char *p, buf[1024];
|
||||
if (!force) {
|
||||
if (IsGenuineCosmo()) return 0;
|
||||
if (__getenv(__envp, "HEISENDEBUG")) return 0;
|
||||
if (getenv("HEISENDEBUG")) return 0;
|
||||
}
|
||||
if (IsWindows()) {
|
||||
return NtGetPeb()->BeingDebugged; /* needs noasan */
|
|
@ -30,9 +30,8 @@ bool IsRunningUnderMake(void) {
|
|||
return g_isrunningundermake;
|
||||
}
|
||||
|
||||
textstartup void g_isrunningundermake_init(int argc, char **argv, char **envp,
|
||||
intptr_t *auxv) {
|
||||
g_isrunningundermake = !!__getenv(envp, "MAKEFLAGS");
|
||||
textstartup void g_isrunningundermake_init(void) {
|
||||
g_isrunningundermake = !!getenv("MAKEFLAGS");
|
||||
}
|
||||
|
||||
const void *const g_isrunningundermake_ctor[] initarray = {
|
||||
|
|
|
@ -16,45 +16,46 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/nt/version.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define IsDumb(s) \
|
||||
(s[0] == 'd' && s[1] == 'u' && s[2] == 'm' && s[3] == 'b' && !s[4])
|
||||
|
||||
/**
|
||||
* Returns true if ANSI terminal colors are appropriate.
|
||||
* Indicates if ANSI terminal colors are inappropriate.
|
||||
*
|
||||
* 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:
|
||||
* Normally this variable should be false. We only set it to true if
|
||||
* we're running on an old version of Windows or the environment
|
||||
* variable `TERM` is set to `dumb`.
|
||||
*
|
||||
* We think colors should be the norm, since most software is usually
|
||||
* too conservative about removing them. Rather than using `isatty`
|
||||
* consider using sed for instances where color must be removed:
|
||||
*
|
||||
* 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.:
|
||||
* For some reason, important software is configured by default in many
|
||||
* operating systems, to not only disable colors, but utf-8 too! Here's
|
||||
* an example of how a wrapper script can fix that for `less`.
|
||||
*
|
||||
* #!/bin/sh
|
||||
* LESSCHARSET=UTF-8 exec /usr/bin/less -RS "$@"
|
||||
*
|
||||
* It's that easy fam.
|
||||
* Thank you for using colors!
|
||||
*/
|
||||
bool cancolor(void) {
|
||||
static bool once;
|
||||
static bool result;
|
||||
return 1;
|
||||
if (!once) {
|
||||
result = (!IsWindows() || NtGetVersion() >= kNtVersionWindows10 ||
|
||||
!ischardev(1)) &&
|
||||
!!strcmp(nulltoempty(getenv("DONTANSIMEBRO")), "1") &&
|
||||
!!strcmp(nulltoempty(getenv("TERM")), "dumb");
|
||||
once = true;
|
||||
}
|
||||
return result;
|
||||
bool __nocolor;
|
||||
|
||||
optimizesize textstartup noasan void __nocolor_init(int argc, char **argv,
|
||||
char **envp,
|
||||
intptr_t *auxv) {
|
||||
char *s;
|
||||
__nocolor = (IsWindows() && !IsAtLeastWindows10()) ||
|
||||
((s = getenv("TERM")) && IsDumb(s));
|
||||
}
|
||||
|
||||
const void *const __nocolor_ctor[] initarray = {
|
||||
__nocolor_init,
|
||||
};
|
|
@ -18,6 +18,20 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/log.h"
|
||||
|
||||
const char *GetAddr2linePath(void) {
|
||||
return commandvenv("ADDR2LINE", "addr2line");
|
||||
static const char *__addr2line;
|
||||
|
||||
static textstartup void __addr2line_init() {
|
||||
static bool once;
|
||||
if (!once) {
|
||||
__addr2line = commandvenv("ADDR2LINE", "addr2line");
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *GetAddr2linePath(void) {
|
||||
return __addr2line;
|
||||
}
|
||||
|
||||
const void *const __addr2line_ctor[] initarray = {
|
||||
__addr2line_init,
|
||||
};
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/gc.internal.h"
|
||||
|
@ -47,6 +48,10 @@
|
|||
#define kBacktraceMaxFrames 128
|
||||
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
|
||||
|
||||
static void ShowHint(const char *s) {
|
||||
kprintf("%snote: %s%s%n", SUBTLE, s, RESET);
|
||||
}
|
||||
|
||||
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||
ssize_t got;
|
||||
intptr_t addr;
|
||||
|
@ -59,15 +64,13 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
||||
|
||||
if (!(debugbin = FindDebugBinary())) {
|
||||
if (IsLinux()) {
|
||||
kprintf("warning: can't find debug binary try setting COMDBG%n");
|
||||
}
|
||||
ShowHint("can't find .com.dbg file try setting COMDBG");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(addr2line = GetAddr2linePath())) {
|
||||
if (IsLinux()) {
|
||||
kprintf("warning: can't find addr2line try setting ADDR2LINE%n");
|
||||
ShowHint("can't find addr2line on path or in ADDR2LINE");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -79,7 +82,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
* tooling which can be counted upon.
|
||||
*/
|
||||
if (!IsLinux()) {
|
||||
kprintf("note: won't print addr2line backtrace on non-linux%n");
|
||||
ShowHint("won't print addr2line backtrace on non-linux");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -170,16 +173,14 @@ void ShowBacktrace(int fd, const struct StackFrame *bp) {
|
|||
#ifdef __FNO_OMIT_FRAME_POINTER__
|
||||
/* asan runtime depends on this function */
|
||||
static bool noreentry;
|
||||
--g_ftrace;
|
||||
++g_ftrace;
|
||||
if (!bp) bp = __builtin_frame_address(0);
|
||||
if (!noreentry) {
|
||||
noreentry = true;
|
||||
PrintBacktrace(fd, bp);
|
||||
noreentry = false;
|
||||
} else {
|
||||
kprintf("warning: re-entered ShowBackTrace()%n");
|
||||
}
|
||||
++g_ftrace;
|
||||
--g_ftrace;
|
||||
#else
|
||||
kprintf("ShowBacktrace() needs these flags to show C backtrace:%n"
|
||||
"\t-D__FNO_OMIT_FRAME_POINTER__%n"
|
||||
|
|
|
@ -36,7 +36,7 @@ relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
|
|||
const char *opchar) {
|
||||
__restore_tty(1);
|
||||
kprintf("%n%serror: %s: check failed: 0x%x %s 0x%x (%s)%n",
|
||||
!g_isterminalinarticulate ? "\e[J" : "", program_invocation_name,
|
||||
want, opchar, got, strerror(errno));
|
||||
!__nocolor ? "\e[J" : "", program_invocation_name, want, opchar, got,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_LOG_COLOR_H_
|
||||
#define COSMOPOLITAN_LIBC_LOG_COLOR_H_
|
||||
#include "libc/log/internal.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define CLS (cancolor() ? "\r\e[J" : "")
|
||||
#define RED (cancolor() ? "\e[30;101m" : "")
|
||||
#define GREEN (cancolor() ? "\e[32m" : "")
|
||||
#define UNBOLD (cancolor() ? "\e[22m" : "")
|
||||
#define RED2 (cancolor() ? "\e[91;1m" : "")
|
||||
#define BLUE1 (cancolor() ? "\e[94;49m" : "")
|
||||
#define BLUE2 (cancolor() ? "\e[34m" : "")
|
||||
#define RESET (cancolor() ? "\e[0m" : "")
|
||||
#define SUBTLE (cancolor() ? "\e[35m" : "")
|
||||
#define CLS (!__nocolor ? "\r\e[J" : "")
|
||||
#define RED (!__nocolor ? "\e[30;101m" : "")
|
||||
#define GREEN (!__nocolor ? "\e[32m" : "")
|
||||
#define UNBOLD (!__nocolor ? "\e[22m" : "")
|
||||
#define RED2 (!__nocolor ? "\e[91;1m" : "")
|
||||
#define BLUE1 (!__nocolor ? "\e[94;49m" : "")
|
||||
#define BLUE2 (!__nocolor ? "\e[34m" : "")
|
||||
#define RESET (!__nocolor ? "\e[0m" : "")
|
||||
#define SUBTLE (!__nocolor ? "\e[35m" : "")
|
||||
|
||||
bool cancolor(void) nothrow nocallback nosideeffect;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_LOG_COLOR_H_ */
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
* or the environment variable was empty; noting that the caller
|
||||
* should copy this string before saving it
|
||||
*/
|
||||
noasan const char *commandvenv(const char *var, const char *cmd) {
|
||||
const char *commandvenv(const char *var, const char *cmd) {
|
||||
const char *exepath;
|
||||
static char pathbuf[PATH_MAX];
|
||||
if (*cmd == '/' || *cmd == '\\') return cmd;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_
|
||||
#define COSMOPOLITAN_LIBC_LOG_COUNTBRANCH_H_
|
||||
#include "libc/macros.internal.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)
|
||||
COUNTBRANCH__(x, STRINGIFY(xs), STRINGIFY(xs), file, line)
|
||||
#define COUNTBRANCH__(x, xs, xss, file, line) \
|
||||
({ \
|
||||
bool Cond; \
|
||||
|
@ -46,7 +46,7 @@ struct countbranch {
|
|||
const char *code;
|
||||
const char *xcode;
|
||||
const char *file;
|
||||
int line;
|
||||
long line;
|
||||
};
|
||||
|
||||
extern struct countbranch countbranch_data[];
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/countbranch.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
|
@ -35,7 +37,7 @@ static double GetPercent(const struct countbranch *p) {
|
|||
}
|
||||
}
|
||||
|
||||
static double RankCounter(const struct countbranch *p) {
|
||||
static int RankCounter(const struct countbranch *p) {
|
||||
double x;
|
||||
x = GetPercent(p);
|
||||
x = MIN(x, 100 - x);
|
||||
|
@ -65,18 +67,28 @@ static void SortCounters(size_t n) {
|
|||
}
|
||||
|
||||
void countbranch_report(void) {
|
||||
double r;
|
||||
size_t i, n;
|
||||
int pct, nines;
|
||||
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);
|
||||
if (p->total) {
|
||||
r = (double)p->taken / p->total;
|
||||
pct = floor(r * 100);
|
||||
nines = floor(fmod(r * 100, 1) * 100000);
|
||||
} else {
|
||||
dprintf(2, "%s:%d: %g%% taken (%,ld/%,ld) %s\n", p->file, p->line,
|
||||
GetPercent(p), p->taken, p->total, p->code);
|
||||
pct = 0;
|
||||
nines = 0;
|
||||
}
|
||||
if (strcmp(p->code, p->xcode)) {
|
||||
kprintf("%s:%-4d: %3d.%05d%% taken (%'ld/%'ld) %s [%s]\n", p->file,
|
||||
p->line, pct, nines, p->taken, p->total, p->code, p->xcode);
|
||||
} else {
|
||||
kprintf("%s:%-4d: %3d.%05d%% taken (%'ld/%'ld) %s\n", p->file, p->line,
|
||||
pct, nines, p->taken, p->total, p->code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
85
libc/log/countexpr.h
Normal file
85
libc/log/countexpr.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_LOG_COUNTEXPR_H_
|
||||
#define COSMOPOLITAN_LIBC_LOG_COUNTEXPR_H_
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/bench.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* Shows nanosecond timings histogram for expr at exit().
|
||||
*/
|
||||
#define COUNTEXPR(expr) \
|
||||
COUNTEXPR_(expr, #expr, STRINGIFY(__FILE__), __LINE__, rdtsc, rdtsc, \
|
||||
"COUNTEXPR")
|
||||
|
||||
/**
|
||||
* Like COUNTEXPR() but can be used on function calls that return void.
|
||||
*/
|
||||
#define COUNTSTMT(stmt) \
|
||||
(void)COUNTEXPR_((stmt, 0), #stmt, STRINGIFY(__FILE__), __LINE__, rdtsc, \
|
||||
rdtsc, "COUNTSTMT")
|
||||
|
||||
/**
|
||||
* Same as COUNTEXPR() but uses Intel's expensive measurement technique.
|
||||
*/
|
||||
#define BENCHEXPR(expr) \
|
||||
COUNTEXPR_(expr, #expr, STRINGIFY(__FILE__), __LINE__, __startbench, \
|
||||
__endbench, "BENCHEXPR")
|
||||
|
||||
#define COUNTEXPR_(expr, code, file, line, start, stop, macro) \
|
||||
COUNTEXPR__(expr, STRINGIFY(code), file, line, start, stop, STRINGIFY(macro))
|
||||
|
||||
#define COUNTEXPR__(expr, code, file, line, start, stop, macro) \
|
||||
({ \
|
||||
struct countexpr *InfO; \
|
||||
uint64_t t1_, t2_, TiCkS, NaNoS; \
|
||||
t1_ = start(); \
|
||||
asm volatile("" ::: "memory"); \
|
||||
autotype(expr) ReS = (expr); \
|
||||
asm volatile("" ::: "memory"); \
|
||||
t2_ = stop(); \
|
||||
TiCkS = t2_ >= t1_ ? t2_ - t1_ : ~t1_ + t2_ + 1; \
|
||||
asm(".section .rodata.str1.1,\"aMS\",@progbits,1\n\t" \
|
||||
".align\t1\n" \
|
||||
"31340:\t.asciz\t" file "\n\t" \
|
||||
"31338:\t.asciz\t" code "\n" \
|
||||
"31332:\t.asciz\t" macro "\n" \
|
||||
".previous\n\t" \
|
||||
".section .yoink\n\t" \
|
||||
"nopl\tcountexpr_data(%%rip)\n\t" \
|
||||
".previous\n\t" \
|
||||
".section .sort.data.countexpr.2,\"a\",@progbits\n\t" \
|
||||
".align\t8\n31337:\t" \
|
||||
".quad\t" #line "\n\t" \
|
||||
".quad\t31340b\n\t" \
|
||||
".quad\t31338b\n\t" \
|
||||
".quad\t31332b\n\t" \
|
||||
".rept\t65\n\t" \
|
||||
".quad\t0\n\t" \
|
||||
".endr\n\t" \
|
||||
".previous\n\t" \
|
||||
"lea\t31337b(%%rip),%0" \
|
||||
: "=r"(InfO)); \
|
||||
/* approximation of round(x*.323018) which is usually */ \
|
||||
/* the ratio, between x86 rdtsc ticks and nanoseconds */ \
|
||||
NaNoS = (TiCkS * 338709) >> 20; \
|
||||
++InfO->logos[NaNoS ? bsrl(NaNoS) + 1 : 0]; \
|
||||
ReS; \
|
||||
})
|
||||
|
||||
struct countexpr {
|
||||
long line; /* zero for last entry */
|
||||
const char *file;
|
||||
const char *code;
|
||||
const char *macro;
|
||||
long logos[65];
|
||||
};
|
||||
|
||||
extern struct countexpr countexpr_data[];
|
||||
|
||||
void countexpr_report(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_LOG_COUNTEXPR_H_ */
|
33
libc/log/countexpr_data.S
Normal file
33
libc/log/countexpr_data.S
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- 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"
|
||||
#include "libc/notice.inc"
|
||||
|
||||
.yoink countexpr_report
|
||||
|
||||
.section .sort.data.countexpr.1,"a",@progbits
|
||||
.align 8
|
||||
.globl countexpr_data
|
||||
countexpr_data:
|
||||
.previous
|
||||
|
||||
.section .sort.data.countexpr.3,"a",@progbits
|
||||
.align 8
|
||||
.quad 0
|
||||
.previous
|
82
libc/log/countexpr_report.c
Normal file
82
libc/log/countexpr_report.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/countexpr.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
static long GetLongSum(const long *h, size_t n) {
|
||||
long t;
|
||||
size_t i;
|
||||
for (t = i = 0; i < n; ++i) {
|
||||
if (__builtin_add_overflow(t, h[i], &t)) {
|
||||
t = LONG_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static size_t GetRowCount(const long *h, size_t n) {
|
||||
while (n && !h[n - 1]) --n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void PrintHistogram(const long *h, size_t n, long t) {
|
||||
size_t i;
|
||||
long j, p;
|
||||
char s[101];
|
||||
unsigned long logos;
|
||||
for (i = 0; i < n; ++i) {
|
||||
p = (h[i] * 10000 + (t >> 1)) / t;
|
||||
assert(0 <= p && p <= 10000);
|
||||
if (p) {
|
||||
for (j = 0; j < p / 100; ++j) s[j] = '#';
|
||||
s[j] = 0;
|
||||
logos = i ? 1ul << (i - 1) : 0;
|
||||
kprintf("%'12lu %'16ld %3d.%02d%% %s%n", logos, h[i], p / 100, p % 100,
|
||||
s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void countexpr_report(void) {
|
||||
long hits;
|
||||
struct countexpr *p;
|
||||
for (p = countexpr_data; p->line; ++p) {
|
||||
if ((hits = GetLongSum(p->logos, 64))) {
|
||||
kprintf("%s:%d: %s(%s) %'ld hits\n", p->file, p->line, p->macro, p->code,
|
||||
hits);
|
||||
PrintHistogram(p->logos, 64, hits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static textstartup void countexpr_init() {
|
||||
atexit(countexpr_report);
|
||||
}
|
||||
|
||||
const void *const countexpr_ctor[] initarray = {
|
||||
countexpr_init,
|
||||
};
|
|
@ -25,12 +25,8 @@
|
|||
* @return symbol table, or NULL w/ errno on first call
|
||||
*/
|
||||
noasan struct SymbolTable *GetSymbolTable(void) {
|
||||
/* asan runtime depends on this function */
|
||||
static bool once;
|
||||
static struct SymbolTable *singleton;
|
||||
const char *debugbin;
|
||||
if (!once) {
|
||||
once = true;
|
||||
if (!singleton) {
|
||||
++g_ftrace;
|
||||
singleton = OpenSymbolTable(FindDebugBinary());
|
||||
--g_ftrace;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
@ -34,7 +35,7 @@
|
|||
* @returns -1 on error or something else on success
|
||||
*/
|
||||
int getttysize(int fd, struct winsize *out) {
|
||||
if (IsTerminalInarticulate()) {
|
||||
if (__nocolor) {
|
||||
out->ws_col = strtoimax(firstnonnull(getenv("COLUMNS"), "80"), NULL, 0);
|
||||
out->ws_row = strtoimax(firstnonnull(getenv("ROWS"), "40"), NULL, 0);
|
||||
out->ws_xpixel = 0;
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern hidden bool __nocolor;
|
||||
extern hidden int kCrashSigs[7];
|
||||
extern hidden bool g_isrunningundermake;
|
||||
extern hidden bool g_isterminalinarticulate;
|
||||
extern hidden struct termios g_oldtermios;
|
||||
extern hidden struct sigaction g_oldcrashacts[7];
|
||||
|
||||
|
|
|
@ -69,10 +69,10 @@ static noasan bool HasLeaks(void) {
|
|||
* services that depend on malloc() cannot be used, after calling this
|
||||
* function.
|
||||
*/
|
||||
noasan void testlib_checkformemoryleaks(void) {
|
||||
noasan void CheckForMemoryLeaks(void) {
|
||||
struct mallinfo mi;
|
||||
if (!cmpxchg(&once, false, true)) {
|
||||
kprintf("testlib_checkformemoryleaks() may only be called once\n");
|
||||
kprintf("CheckForMemoryLeaks() may only be called once\n");
|
||||
exit(1);
|
||||
}
|
||||
__cxa_finalize(0);
|
|
@ -11,6 +11,8 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define __ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
extern char __fatalbuf[];
|
||||
|
||||
forceinline long __sysv_exit(long rc) {
|
||||
|
@ -113,8 +115,6 @@ forceinline int __getpid(void) {
|
|||
}
|
||||
|
||||
forceinline ssize_t __write(const void *p, size_t n) {
|
||||
char cf;
|
||||
ssize_t rc;
|
||||
uint32_t wrote;
|
||||
if (!IsWindows()) {
|
||||
return __sysv_write(2, p, n);
|
||||
|
@ -157,25 +157,23 @@ forceinline void *__repstosb(void *di, char al, size_t cx) {
|
|||
: "0"(di), "1"(cx), "a"(al));
|
||||
return di;
|
||||
#else
|
||||
size_t i;
|
||||
volatile char *volatile d = di;
|
||||
while (cx--) *d++ = al;
|
||||
return d;
|
||||
return (void *)d;
|
||||
#endif
|
||||
}
|
||||
|
||||
forceinline void *__repmovsb(void *di, void *si, size_t cx) {
|
||||
forceinline void *__repmovsb(void *di, const void *si, size_t cx) {
|
||||
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
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;
|
||||
#else
|
||||
size_t i;
|
||||
volatile char *volatile d = di;
|
||||
volatile char *volatile s = si;
|
||||
while (cx--) *d++ = *s++;
|
||||
return d;
|
||||
return (void *)d;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -244,24 +242,12 @@ forceinline char *__strstr(const char *haystack, const char *needle) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
forceinline char *__getenv(char **p, const char *s) {
|
||||
size_t i, j;
|
||||
if (p) {
|
||||
for (i = 0; p[i]; ++i) {
|
||||
for (j = 0;; ++j) {
|
||||
if (!s[j]) {
|
||||
if (p[i][j] == '=') {
|
||||
return p[i] + j + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (s[j] != p[i][j]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
forceinline const char *__strchr(const char *s, unsigned char c) {
|
||||
char *r;
|
||||
for (;; ++s) {
|
||||
if ((*s & 255) == c) return s;
|
||||
if (!*s) return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
forceinline unsigned long __atoul(const char *p) {
|
||||
|
|
|
@ -58,6 +58,7 @@ void AppendResourceReport(char **, struct rusage *, const char *);
|
|||
char *__get_symbol_by_addr(int64_t);
|
||||
void PrintGarbage(void);
|
||||
void PrintGarbageNumeric(FILE *);
|
||||
void CheckForMemoryLeaks(void);
|
||||
|
||||
#define showcrashreports() ShowCrashReports()
|
||||
|
||||
|
|
|
@ -63,6 +63,10 @@ o/$(MODE)/libc/log/backtrace3.o: \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-fno-sanitize=all
|
||||
|
||||
o/$(MODE)/libc/log/checkfail.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-mgeneral-regs-only
|
||||
|
||||
o/$(MODE)/libc/log/attachdebugger.o \
|
||||
o/$(MODE)/libc/log/backtrace2.o \
|
||||
o/$(MODE)/libc/log/backtrace3.o \
|
||||
|
@ -70,7 +74,6 @@ 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 \
|
||||
|
|
|
@ -18,50 +18,27 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/utsname.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.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"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#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"
|
||||
|
||||
/**
|
||||
* @fileoverview Abnormal termination handling & GUI debugging.
|
||||
* @see libc/onkill.c
|
||||
*/
|
||||
|
||||
STATIC_YOINK("strerror_r");
|
||||
STATIC_YOINK("strerror_r"); /* for kprintf %m */
|
||||
|
||||
static const char kGregOrder[17] forcealign(1) = {
|
||||
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||
|
@ -89,7 +66,7 @@ static const char kCrashSigNames[7][5] forcealign(1) = {
|
|||
};
|
||||
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||
|
||||
static relegated noasan noinstrument const char *TinyStrSignal(int sig) {
|
||||
static relegated noinstrument const char *TinyStrSignal(int sig) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
|
||||
|
@ -111,7 +88,6 @@ relegated static void ShowFunctionCalls(ucontext_t *ctx) {
|
|||
goodframe.addr = ctx->uc_mcontext.rip;
|
||||
bp = &goodframe;
|
||||
ShowBacktrace(2, bp);
|
||||
kprintf("%n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +133,7 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
|
|||
long double st;
|
||||
char *p, buf[128];
|
||||
p = buf;
|
||||
printf("%n");
|
||||
kprintf("%n");
|
||||
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
|
||||
if (j > 0) *p++ = ' ';
|
||||
if (!(s = kGregNames[(unsigned)kGregOrder[i]])[2]) *p++ = ' ';
|
||||
|
@ -248,8 +224,8 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
|||
" %s%n"
|
||||
" %m%n"
|
||||
" %s %s %s %s%n",
|
||||
!g_isterminalinarticulate ? "\e[30;101m" : "",
|
||||
!g_isterminalinarticulate ? "\e[0m" : "", TinyStrSignal(sig),
|
||||
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "",
|
||||
TinyStrSignal(sig),
|
||||
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
||||
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
|
||||
? "Stack Overflow"
|
||||
|
@ -285,8 +261,10 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static wontreturn noasan relegated noinstrument void __minicrash(
|
||||
int sig, struct siginfo *si, ucontext_t *ctx, const char *kind) {
|
||||
static wontreturn relegated noinstrument void __minicrash(int sig,
|
||||
struct siginfo *si,
|
||||
ucontext_t *ctx,
|
||||
const char *kind) {
|
||||
kprintf("%n"
|
||||
"%n"
|
||||
"CRASHED %s WITH SIG%s%n"
|
||||
|
@ -313,8 +291,8 @@ static wontreturn noasan relegated noinstrument void __minicrash(
|
|||
*
|
||||
* This function never returns, except for traps w/ human supervision.
|
||||
*/
|
||||
noasan relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
||||
ucontext_t *ctx) {
|
||||
relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
||||
ucontext_t *ctx) {
|
||||
intptr_t rip;
|
||||
int gdbpid, err;
|
||||
static bool noreentry, notpossible;
|
||||
|
@ -325,7 +303,7 @@ noasan relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
|||
err = errno;
|
||||
if ((gdbpid = IsDebuggerPresent(true))) {
|
||||
DebugBreak();
|
||||
} else if (g_isterminalinarticulate || g_isrunningundermake) {
|
||||
} else if (__nocolor || g_isrunningundermake) {
|
||||
gdbpid = -1;
|
||||
} else if (IsLinux() && FindDebugBinary()) {
|
||||
RestoreDefaultCrashSignalHandlers();
|
||||
|
|
|
@ -17,13 +17,19 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.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"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Terminal Restoration Helper
|
||||
*
|
||||
* This is used by the crash reporting functions, e.g. __die(), to help
|
||||
* ensure the terminal is in an unborked state after a crash happens.
|
||||
*/
|
||||
|
||||
#define RESET_COLOR "\e[0m"
|
||||
#define SHOW_CURSOR "\e[?25h"
|
||||
|
@ -32,13 +38,10 @@
|
|||
|
||||
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() {
|
||||
int e = errno;
|
||||
tcgetattr(1, &g_oldtermios);
|
||||
errno = e;
|
||||
}
|
||||
|
||||
const void *const g_oldtermios_ctor[] initarray = {
|
||||
|
@ -46,7 +49,7 @@ const void *const g_oldtermios_ctor[] initarray = {
|
|||
};
|
||||
|
||||
void __restore_tty(int fd) {
|
||||
if (g_oldtermios.c_lflag && isatty(fd) && cancolor()) {
|
||||
if (g_oldtermios.c_lflag && !__nocolor && isatty(fd)) {
|
||||
write(fd, ANSI_RESTORE, strlen(ANSI_RESTORE));
|
||||
tcsetattr(fd, TCSAFLUSH, &g_oldtermios);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ void ShowCrashReports(void) {
|
|||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
sigdelset(&sa.sa_mask, kCrashSigs[i]);
|
||||
}
|
||||
sigaltstack(&ss, 0);
|
||||
if (!IsWindows()) sigaltstack(&ss, 0);
|
||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
if (kCrashSigs[i]) {
|
||||
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
|
@ -27,19 +27,8 @@
|
|||
* @note this is support code for __check_fail(), __assert_fail(), etc.
|
||||
*/
|
||||
relegated void __start_fatal(const char *file, int line) {
|
||||
bool colorful;
|
||||
char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p = s;
|
||||
__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 = __intcpy(p, line), *p++ = ':';
|
||||
p = __stpcpy(p, program_invocation_short_name);
|
||||
if (colorful) p = __stpcpy(p, "\e[0m");
|
||||
*p++ = ':';
|
||||
*p++ = ' ';
|
||||
__write(s, p - s);
|
||||
kprintf("\r%serror%s:%s:%d:%s%s: ", !__nocolor ? "\e[J\e[30;101m" : "",
|
||||
!__nocolor ? "\e[94;49m" : "", file, line,
|
||||
program_invocation_short_name, !__nocolor ? "\e[0m" : "");
|
||||
}
|
||||
|
|
|
@ -192,3 +192,31 @@
|
|||
#endif
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro .poison name:req kind:req
|
||||
#ifdef __FSANITIZE_ADDRESS__
|
||||
2323: .quad 0
|
||||
.init.start 304,"_init_\name\()_poison_\@"
|
||||
push %rdi
|
||||
push %rsi
|
||||
ezlea 2323b,di
|
||||
mov $8,%esi
|
||||
mov $\kind,%edx
|
||||
call __asan_poison
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
.init.end 304,"_init_\name\()_poison_\@"
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro .underrun
|
||||
#ifdef __FSANITIZE_ADDRESS__
|
||||
.poison __BASE_FILE__ kAsanGlobalUnderrun
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro .overrun
|
||||
#ifdef __FSANITIZE_ADDRESS__
|
||||
.poison __BASE_FILE__ kAsanGlobalUnderrun
|
||||
#endif
|
||||
.endm
|
||||
|
|
|
@ -17,46 +17,63 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define MAX_VARS 512
|
||||
|
||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
static bool once;
|
||||
static size_t capacity;
|
||||
|
||||
static void PutEnvDestroy(void) {
|
||||
static size_t GetEnvironLen(char **env) {
|
||||
char **p = env;
|
||||
while (*p) ++p;
|
||||
return p - env;
|
||||
}
|
||||
|
||||
static void RestoreOriginalEnvironment(char **envp) {
|
||||
environ = envp;
|
||||
}
|
||||
|
||||
static void PutEnvImplAtExit(void *p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
static void FreeEnviron(char **env) {
|
||||
char **a;
|
||||
for (a = environ; *a; ++a) free(*a);
|
||||
free(environ);
|
||||
}
|
||||
|
||||
static void PutEnvInit(void) {
|
||||
char **pin, **pout;
|
||||
pin = environ;
|
||||
pout = malloc(sizeof(char *) * MAX_VARS);
|
||||
environ = pout;
|
||||
while (*pin) *pout++ = strdup(*pin++);
|
||||
*pout = NULL;
|
||||
atexit(PutEnvDestroy);
|
||||
}
|
||||
|
||||
void __freeenv(void *p) {
|
||||
if (once) {
|
||||
free(p);
|
||||
for (a = env; *a; ++a) {
|
||||
free(*a);
|
||||
}
|
||||
free(env);
|
||||
}
|
||||
|
||||
static void GrowEnviron(void) {
|
||||
size_t n, c;
|
||||
char **a, **b, **p;
|
||||
a = environ;
|
||||
n = GetEnvironLen(a);
|
||||
c = MAX(16ul, n) << 1;
|
||||
b = calloc(c, sizeof(char *));
|
||||
for (p = b; *a;) {
|
||||
*p++ = strdup(*a++);
|
||||
}
|
||||
__cxa_atexit(FreeEnviron, b, 0);
|
||||
environ = b;
|
||||
capacity = c;
|
||||
}
|
||||
|
||||
int PutEnvImpl(char *s, bool overwrite) {
|
||||
char *p;
|
||||
unsigned i, namelen;
|
||||
if (!once) {
|
||||
PutEnvInit();
|
||||
__cxa_atexit(RestoreOriginalEnvironment, environ, 0);
|
||||
GrowEnviron();
|
||||
once = true;
|
||||
}
|
||||
for (p = s; *p && *p != '='; ++p) {
|
||||
|
@ -64,7 +81,7 @@ int PutEnvImpl(char *s, bool overwrite) {
|
|||
*p = ToUpper(*p);
|
||||
}
|
||||
}
|
||||
if (*p != '=') goto fail;
|
||||
if (*p != '=') goto Fail;
|
||||
namelen = p + 1 - s;
|
||||
for (i = 0; environ[i]; ++i) {
|
||||
if (!strncmp(environ[i], s, namelen)) {
|
||||
|
@ -72,27 +89,38 @@ int PutEnvImpl(char *s, bool overwrite) {
|
|||
free(s);
|
||||
return 0;
|
||||
}
|
||||
goto replace;
|
||||
goto Replace;
|
||||
}
|
||||
}
|
||||
if (i + 1 >= MAX_VARS) {
|
||||
free(s);
|
||||
return enomem();
|
||||
if (i + 1 >= capacity) {
|
||||
GrowEnviron();
|
||||
}
|
||||
environ[i + 1] = NULL;
|
||||
replace:
|
||||
free(environ[i]);
|
||||
environ[i + 1] = 0;
|
||||
Replace:
|
||||
__cxa_atexit(PutEnvImplAtExit, environ[i], 0);
|
||||
environ[i] = s;
|
||||
return 0;
|
||||
fail:
|
||||
Fail:
|
||||
free(s);
|
||||
return einval();
|
||||
}
|
||||
|
||||
/* weakly called by unsetenv() when removing a pointer */
|
||||
void __freeenv(void *p) {
|
||||
if (once) {
|
||||
__cxa_atexit(free, p, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emplaces environment key=value.
|
||||
*
|
||||
* @return 0 on success or non-zero on error
|
||||
* @see setenv(), getenv()
|
||||
*/
|
||||
int putenv(char *string) {
|
||||
return PutEnvImpl(strdup(string), true);
|
||||
int putenv(char *s) {
|
||||
int rc;
|
||||
rc = PutEnvImpl(strdup(s), true);
|
||||
SYSDEBUG("putenv(%#s) → %d", s, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/mem/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -28,9 +29,14 @@
|
|||
* @see putenv(), getenv()
|
||||
*/
|
||||
int setenv(const char *name, const char *value, int overwrite) {
|
||||
size_t namelen = strlen(name);
|
||||
size_t valuelen = strlen(value);
|
||||
char *s = malloc(namelen + valuelen + 2);
|
||||
int rc;
|
||||
char *s;
|
||||
size_t namelen, valuelen;
|
||||
namelen = strlen(name);
|
||||
valuelen = strlen(value);
|
||||
s = malloc(namelen + valuelen + 2);
|
||||
memcpy(mempcpy(mempcpy(s, name, namelen), "=", 1), value, valuelen + 1);
|
||||
return PutEnvImpl(s, overwrite);
|
||||
rc = PutEnvImpl(s, overwrite);
|
||||
SYSDEBUG("setenv(%#s, %#s, %d) → %d", name, value, overwrite, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,15 +17,40 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
static char *g_comdbg;
|
||||
static char g_comdbg_buf[PATH_MAX + 1];
|
||||
|
||||
static optimizesize textstartup void g_comdbg_init() {
|
||||
char *p;
|
||||
size_t n;
|
||||
static bool once;
|
||||
if (!once) {
|
||||
if (!(g_comdbg = getenv("COMDBG"))) {
|
||||
p = program_executable_name;
|
||||
n = strlen(p);
|
||||
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
||||
g_comdbg = p;
|
||||
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
||||
n + 4 <= PATH_MAX) {
|
||||
mempcpy(mempcpy(g_comdbg_buf, p, n), ".dbg", 5);
|
||||
if (fileexists(g_comdbg_buf)) {
|
||||
g_comdbg = g_comdbg_buf;
|
||||
}
|
||||
} else if (n + 8 <= PATH_MAX) {
|
||||
mempcpy(mempcpy(g_comdbg_buf, p, n), ".com.dbg", 9);
|
||||
if (fileexists(g_comdbg_buf)) {
|
||||
g_comdbg = g_comdbg_buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns path of binary with the debug information, or null.
|
||||
|
@ -33,31 +58,10 @@
|
|||
* @return path to debug binary, or NULL
|
||||
*/
|
||||
const char *FindDebugBinary(void) {
|
||||
static bool once;
|
||||
static char *res;
|
||||
static char buf[PATH_MAX + 1];
|
||||
char *p;
|
||||
size_t n;
|
||||
if (!once) {
|
||||
if (!(res = getenv("COMDBG"))) {
|
||||
p = program_executable_name;
|
||||
n = strlen(p);
|
||||
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
||||
res = p;
|
||||
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
||||
n + 4 <= PATH_MAX) {
|
||||
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
|
||||
if (fileexists(buf)) {
|
||||
res = buf;
|
||||
}
|
||||
} else if (n + 8 <= PATH_MAX) {
|
||||
mempcpy(mempcpy(buf, p, n), ".com.dbg", 9);
|
||||
if (fileexists(buf)) {
|
||||
res = buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
return res;
|
||||
g_comdbg_init();
|
||||
return g_comdbg;
|
||||
}
|
||||
|
||||
const void *const g_comdbg_ctor[] initarray = {
|
||||
g_comdbg_init,
|
||||
};
|
||||
|
|
|
@ -61,6 +61,10 @@ static optimizesize noasan void longsort_pure(long *x, size_t n, size_t t) {
|
|||
|
||||
/**
|
||||
* Sorting algorithm for longs that doesn't take long.
|
||||
*
|
||||
* "What disorder is this? Give me my long sort!"
|
||||
* -Lord Capulet
|
||||
*
|
||||
*/
|
||||
void longsort(long *x, size_t n) {
|
||||
size_t t, m;
|
||||
|
|
|
@ -352,7 +352,6 @@ void thrashcodecache(void);
|
|||
void testlib_finish(void);
|
||||
void testlib_runalltests(void);
|
||||
void testlib_runallbenchmarks(void);
|
||||
void testlib_checkformemoryleaks(void);
|
||||
void testlib_runtestcases(testfn_t *, testfn_t *, testfn_t);
|
||||
void testlib_runcombos(testfn_t *, testfn_t *, const struct TestFixture *,
|
||||
const struct TestFixture *);
|
||||
|
|
|
@ -59,7 +59,6 @@ LIBC_TESTLIB_A_SRCS_C = \
|
|||
libc/testlib/comborunner.c \
|
||||
libc/testlib/contains.c \
|
||||
libc/testlib/endswith.c \
|
||||
libc/testlib/leaks.c \
|
||||
libc/testlib/yield.c \
|
||||
libc/testlib/ezbenchcontrol.c \
|
||||
libc/testlib/ezbenchreport.c \
|
||||
|
|
|
@ -95,13 +95,13 @@ noasan int main(int argc, char *argv[]) {
|
|||
if (!g_testlib_failed && runbenchmarks_ && weaken(testlib_runallbenchmarks)) {
|
||||
weaken(testlib_runallbenchmarks)();
|
||||
if (!g_testlib_failed) {
|
||||
testlib_checkformemoryleaks();
|
||||
CheckForMemoryLeaks();
|
||||
}
|
||||
if (!g_testlib_failed && IsRunningUnderMake()) {
|
||||
return 254; /* compile.com considers this 0 and propagates output */
|
||||
}
|
||||
} else if (!g_testlib_failed) {
|
||||
testlib_checkformemoryleaks();
|
||||
CheckForMemoryLeaks();
|
||||
}
|
||||
exit(min(255, g_testlib_failed));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue