mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-14 15:09:09 +00:00
Make improvements
- Fix build flakes - Polyfill SIGWINCH on Windows - Fix an execve issue on Windows - Make strerror show more information - Improve cmd.exe setup/teardown on Windows - Support bracketed paste mode in Blinkenlights - Show keyboard shortcuts in Blinkenlights status bar - Fixed copy_file_range() and copyfile() w/ zip filesystem - Size optimize GetDosArgv() to keep life.com 12kb in size - Improve Blinkenlights ability to load weird ELF executables - Fix program_executable_name and add GetInterpreterExecutableName - Make Python in tiny mode fail better if docstrings are requested - Update Python test exclusions in tiny* modes such as tinylinux - Add bulletproof unbreakable kprintf() troubleshooting function - Remove "oldskool" keyword from ape.S for virus scanners - Fix issue that caused backtraces to not print sometimes - Improve Blinkenlights serial uart character i/o - Make clock_gettime() not clobber errno on xnu - Improve sha256 cpuid check for old computers - Integrate some bestline linenoise fixes - Show runit process names better in htop - Remove SIGPIPE from ShowCrashReports() - Make realpath() not clobber errno - Avoid attaching GDB on non-Linux - Improve img.com example
This commit is contained in:
parent
2a938b3eaa
commit
b45d50b690
194 changed files with 4881 additions and 2966 deletions
|
@ -22,10 +22,11 @@
|
|||
#include "libc/bits/likely.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
@ -89,12 +90,13 @@ STATIC_YOINK("_init_asan");
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE(FUNC) \
|
||||
do { \
|
||||
if (!weaken(FUNC)) { \
|
||||
__asan_die("error: asan needs " #FUNC "\n")(); \
|
||||
__asan_unreachable(); \
|
||||
} \
|
||||
#define REQUIRE(FUNC) \
|
||||
do { \
|
||||
if (!weaken(FUNC)) { \
|
||||
kprintf("error: asan needs %s%n", #FUNC); \
|
||||
__asan_die()(); \
|
||||
__asan_unreachable(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
|
@ -139,6 +141,7 @@ struct AsanMorgue {
|
|||
};
|
||||
|
||||
bool __asan_noreentry;
|
||||
extern bool __nomultics;
|
||||
static struct AsanMorgue __asan_morgue;
|
||||
|
||||
static wontreturn void __asan_unreachable(void) {
|
||||
|
@ -227,7 +230,8 @@ static void *__asan_memset(void *p, char c, size_t n) {
|
|||
|
||||
static void *__asan_mempcpy(void *dst, const void *src, size_t n) {
|
||||
size_t i;
|
||||
char *d, *s;
|
||||
char *d;
|
||||
const char *s;
|
||||
uint64_t a, b;
|
||||
d = dst;
|
||||
s = src;
|
||||
|
@ -303,14 +307,13 @@ static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
|
|||
}
|
||||
|
||||
static void __asan_exit(void) {
|
||||
__printf("your asan runtime needs\n"
|
||||
"\tSTATIC_YOINK(\"__die\");\n"
|
||||
"in order to show you backtraces\n");
|
||||
kprintf("your asan runtime needs%n"
|
||||
"\tSTATIC_YOINK(\"__die\");%n"
|
||||
"in order to show you backtraces%n");
|
||||
_Exit(99);
|
||||
}
|
||||
|
||||
nodiscard static __asan_die_f *__asan_die(const char *msg) {
|
||||
__printf("%s", msg);
|
||||
nodiscard static __asan_die_f *__asan_die(void) {
|
||||
if (weaken(__die)) {
|
||||
return weaken(__die);
|
||||
} else {
|
||||
|
@ -358,7 +361,7 @@ static bool __asan_is_mapped(int x) {
|
|||
struct MemoryIntervals *m;
|
||||
m = weaken(_mmi);
|
||||
i = FindMemoryInterval(m, x);
|
||||
return i < m->i && m->p[i].x <= x && x <= m->p[i].y;
|
||||
return i < m->i && x >= m->p[i].x;
|
||||
}
|
||||
|
||||
static bool __asan_is_image(const unsigned char *p) {
|
||||
|
@ -366,7 +369,7 @@ static bool __asan_is_image(const unsigned char *p) {
|
|||
}
|
||||
|
||||
static bool __asan_exists(const void *x) {
|
||||
return __asan_is_image(x) || __asan_is_mapped((intptr_t)x >> 16);
|
||||
return !kisdangerous(x);
|
||||
}
|
||||
|
||||
static struct AsanFault __asan_fault(const signed char *s, signed char dflt) {
|
||||
|
@ -385,13 +388,13 @@ static struct AsanFault __asan_fault(const signed char *s, signed char dflt) {
|
|||
static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
|
||||
intptr_t a;
|
||||
uint64_t w;
|
||||
signed char c, *e = s + ndiv8;
|
||||
const signed char *e = s + ndiv8;
|
||||
for (; ((intptr_t)s & 7) && s < e; ++s) {
|
||||
if (*s) return __asan_fault(s - 1, kAsanHeapOverrun);
|
||||
}
|
||||
for (; s + 8 <= e; s += 8) {
|
||||
if (UNLIKELY(!((a = (intptr_t)s) & 0xffff))) {
|
||||
if (!__asan_is_mapped(a >> 16)) {
|
||||
if (kisdangerous((void *)a)) {
|
||||
return (struct AsanFault){kAsanUnmapped, s};
|
||||
}
|
||||
}
|
||||
|
@ -422,7 +425,6 @@ static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
|
|||
*/
|
||||
struct AsanFault __asan_check(const void *p, long n) {
|
||||
intptr_t a;
|
||||
uint64_t w;
|
||||
struct AsanFault f;
|
||||
signed char c, k, *s;
|
||||
if (n > 0) {
|
||||
|
@ -431,7 +433,7 @@ struct AsanFault __asan_check(const void *p, long n) {
|
|||
s = (signed char *)a;
|
||||
if (OverlapsShadowSpace(p, n)) {
|
||||
return (struct AsanFault){kAsanProtected, s};
|
||||
} else if (IsLegalPointer(a) && !__asan_is_mapped(a >> 16)) {
|
||||
} else if (kisdangerous((void *)a)) {
|
||||
return (struct AsanFault){kAsanUnmapped, s};
|
||||
}
|
||||
if (UNLIKELY(k)) {
|
||||
|
@ -491,19 +493,6 @@ bool __asan_is_valid_strlist(char *const *p) {
|
|||
}
|
||||
}
|
||||
|
||||
static const char *__asan_dscribe_heap_poison(signed char c) {
|
||||
switch (c) {
|
||||
case kAsanHeapFree:
|
||||
return "heap double free";
|
||||
case kAsanStackFree:
|
||||
return "free stack after return";
|
||||
case kAsanHeapRelocated:
|
||||
return "free after relocate";
|
||||
default:
|
||||
return "this corruption";
|
||||
}
|
||||
}
|
||||
|
||||
wint_t __asan_symbolize_access_poison(signed char kind) {
|
||||
switch (kind) {
|
||||
case kAsanNullPage:
|
||||
|
@ -544,6 +533,10 @@ wint_t __asan_symbolize_access_poison(signed char kind) {
|
|||
return L'G';
|
||||
case kAsanGlobalGone:
|
||||
return L'𝐺';
|
||||
case kAsanGlobalUnderrun:
|
||||
return L'μ';
|
||||
case kAsanGlobalOverrun:
|
||||
return L'Ω';
|
||||
default:
|
||||
return L'?';
|
||||
}
|
||||
|
@ -589,16 +582,19 @@ const char *__asan_describe_access_poison(signed char kind) {
|
|||
return "global redzone";
|
||||
case kAsanGlobalGone:
|
||||
return "global gone";
|
||||
case kAsanGlobalUnderrun:
|
||||
return "global underrun";
|
||||
case kAsanGlobalOverrun:
|
||||
return "global overrun";
|
||||
default:
|
||||
return "poisoned";
|
||||
}
|
||||
}
|
||||
|
||||
nodiscard static __asan_die_f *__asan_report_invalid_pointer(void *addr) {
|
||||
__printf("\r\n%sasan error%s: this corruption at 0x%p shadow 0x%p\r\n",
|
||||
!g_isterminalinarticulate ? "\e[J\e[1;91m" : "",
|
||||
!g_isterminalinarticulate ? "\e[0m" : "", addr, SHADOW(addr));
|
||||
return __asan_die("");
|
||||
nodiscard static __asan_die_f *__asan_report_invalid_pointer(const void *addr) {
|
||||
kprintf("%n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p%n",
|
||||
addr, SHADOW(addr));
|
||||
return __asan_die();
|
||||
}
|
||||
|
||||
static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) {
|
||||
|
@ -607,8 +603,8 @@ static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *__asan_format_section(char *p, void *p1, void *p2,
|
||||
const char *name, void *addr) {
|
||||
static char *__asan_format_section(char *p, const void *p1, const void *p2,
|
||||
const char *name, const void *addr) {
|
||||
intptr_t a, b;
|
||||
if ((a = (intptr_t)p1) < (b = (intptr_t)p2)) {
|
||||
p = __asan_format_interval(p, a, b), *p++ = ' ';
|
||||
|
@ -616,26 +612,25 @@ static char *__asan_format_section(char *p, void *p1, void *p2,
|
|||
if (a <= (intptr_t)addr && (intptr_t)addr <= b) {
|
||||
p = __stpcpy(p, " ←address");
|
||||
}
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
if (__nomultics) *p++ = '\r';
|
||||
*p++ = '\n';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
nodiscard static __asan_die_f *__asan_report(void *addr, int size,
|
||||
nodiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
||||
const char *message,
|
||||
signed char kind) {
|
||||
int i;
|
||||
wint_t c;
|
||||
int i, cc;
|
||||
signed char t;
|
||||
uint64_t x, y, z;
|
||||
char *p, *q, *base;
|
||||
struct MemoryIntervals *m;
|
||||
p = __fatalbuf;
|
||||
__printf("\r\n%sasan error%s: %s %d-byte %s at 0x%p shadow 0x%p\r\n",
|
||||
!g_isterminalinarticulate ? "\e[J\e[1;91m" : "",
|
||||
!g_isterminalinarticulate ? "\e[0m" : "",
|
||||
__asan_describe_access_poison(kind), size, message, addr,
|
||||
SHADOW(addr));
|
||||
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,
|
||||
SHADOW(addr), __argv[0]);
|
||||
if (0 < size && size < 80) {
|
||||
base = (char *)addr - ((80 >> 1) - (size >> 1));
|
||||
for (i = 0; i < 80; ++i) {
|
||||
|
@ -649,30 +644,32 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
|
|||
*p++ = ' ';
|
||||
}
|
||||
}
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
if (__nomultics) *p++ = '\r';
|
||||
*p++ = '\n';
|
||||
for (c = i = 0; i < 80; ++i) {
|
||||
if (!(t = __asan_check(base + i, 1).kind)) {
|
||||
if (!g_isterminalinarticulate && c != 32) {
|
||||
if (c != 32) {
|
||||
p = __stpcpy(p, "\e[32m");
|
||||
c = 32;
|
||||
}
|
||||
*p++ = '.';
|
||||
} else {
|
||||
if (!g_isterminalinarticulate && c != 31) {
|
||||
if (c != 31) {
|
||||
p = __stpcpy(p, "\e[31m");
|
||||
c = 31;
|
||||
}
|
||||
p = __asan_utf8cpy(p, __asan_symbolize_access_poison(t));
|
||||
}
|
||||
}
|
||||
if (!g_isterminalinarticulate) p = __stpcpy(p, "\e[39m");
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
p = __stpcpy(p, "\e[39m");
|
||||
if (__nomultics) *p++ = '\r';
|
||||
*p++ = '\n';
|
||||
for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' ';
|
||||
for (; i + 8 <= 80; i += 8) {
|
||||
q = p + 8;
|
||||
*p++ = '|';
|
||||
z = ((intptr_t)(base + i) >> 3) + 0x7fff8000;
|
||||
if (__asan_is_mapped(z >> 16)) {
|
||||
if (!kisdangerous((void *)z)) {
|
||||
p = __intcpy(p, *(signed char *)z);
|
||||
} else {
|
||||
*p++ = '!';
|
||||
|
@ -682,13 +679,15 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
|
|||
}
|
||||
}
|
||||
for (; i < 80; ++i) *p++ = ' ';
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
if (__nomultics) *p++ = '\r';
|
||||
*p++ = '\n';
|
||||
for (i = 0; i < 80; ++i) {
|
||||
p = __asan_utf8cpy(p, __asan_exists(base + i)
|
||||
? kCp437[((unsigned char *)base)[i]]
|
||||
: L'⋅');
|
||||
}
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
if (__nomultics) *p++ = '\r';
|
||||
*p++ = '\n';
|
||||
}
|
||||
p = __asan_format_section(p, _base, _etext, ".text", addr);
|
||||
p = __asan_format_section(p, _etext, _edata, ".data", addr);
|
||||
|
@ -701,10 +700,12 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
|
|||
if (x <= z && z <= y) p = __stpcpy(p, " ←address");
|
||||
z = (((intptr_t)addr >> 3) + 0x7fff8000) >> 16;
|
||||
if (x <= z && z <= y) p = __stpcpy(p, " ←shadow");
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
if (__nomultics) *p++ = '\r';
|
||||
*p++ = '\n';
|
||||
}
|
||||
*p = 0;
|
||||
return __asan_die(__fatalbuf);
|
||||
kprintf("%s", __fatalbuf);
|
||||
return __asan_die();
|
||||
}
|
||||
|
||||
void __asan_verify(const void *p, size_t n) {
|
||||
|
@ -726,7 +727,7 @@ nodiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size,
|
|||
__asan_fault(SHADOW(addr), -128).kind);
|
||||
}
|
||||
|
||||
const void *__asan_morgue_add(void *p) {
|
||||
void *__asan_morgue_add(void *p) {
|
||||
void *r;
|
||||
int i, j;
|
||||
for (;;) {
|
||||
|
@ -785,6 +786,17 @@ static bool __asan_read48(uint64_t value, uint64_t *x) {
|
|||
return cookie == ('J' | 'T' << 8);
|
||||
}
|
||||
|
||||
static void __asan_rawtrace(struct AsanTrace *bt, const struct StackFrame *bp) {
|
||||
size_t i;
|
||||
for (i = 0; bp && i < ARRAYLEN(bt->p); ++i, bp = bp->next) {
|
||||
if (kisdangerous(bp)) break;
|
||||
bt->p[i] = bp->addr;
|
||||
}
|
||||
for (; i < ARRAYLEN(bt->p); ++i) {
|
||||
bt->p[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
|
||||
int f1, f2;
|
||||
size_t i, gi;
|
||||
|
@ -792,10 +804,9 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
|
|||
struct Garbages *garbage;
|
||||
garbage = weaken(__garbage);
|
||||
gi = garbage ? garbage->i : 0;
|
||||
__asan_memset(bt, 0, sizeof(*bt));
|
||||
for (f1 = -1, i = 0; bp && i < ARRAYLEN(bt->p); ++i, bp = bp->next) {
|
||||
if (f1 != (f2 = ((intptr_t)bp >> 16))) {
|
||||
if (!__asan_is_mapped(f2)) break;
|
||||
if (kisdangerous(bp)) break;
|
||||
f1 = f2;
|
||||
}
|
||||
if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) {
|
||||
|
@ -809,8 +820,13 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
for (; i < ARRAYLEN(bt->p); ++i) {
|
||||
bt->p[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define __asan_trace __asan_rawtrace
|
||||
|
||||
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
|
||||
struct AsanTrace *bt) {
|
||||
char *p;
|
||||
|
@ -830,17 +846,14 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
|
|||
return p;
|
||||
}
|
||||
|
||||
static struct AsanExtra *__asan_get_extra(void *p, size_t *c) {
|
||||
static struct AsanExtra *__asan_get_extra(const void *p, size_t *c) {
|
||||
int f;
|
||||
long x, n;
|
||||
struct AsanExtra *e;
|
||||
if ((0 < (intptr_t)p && (intptr_t)p < 0x800000000000) &&
|
||||
__asan_is_mapped((f = (intptr_t)p >> 16)) &&
|
||||
(LIKELY(f == (int)(((intptr_t)p - 16) >> 16)) ||
|
||||
__asan_is_mapped(((intptr_t)p - 16) >> 16)) &&
|
||||
(n = weaken(dlmalloc_usable_size)(p)) > sizeof(*e) &&
|
||||
f = (intptr_t)p >> 16;
|
||||
if (!kisdangerous(p) && (n = weaken(dlmalloc_usable_size)(p)) > sizeof(*e) &&
|
||||
!__builtin_add_overflow((intptr_t)p, n, &x) && x <= 0x800000000000 &&
|
||||
(LIKELY(f == (int)((x - 1) >> 16)) || __asan_is_mapped((x - 1) >> 16)) &&
|
||||
(LIKELY(f == (int)((x - 1) >> 16)) || !kisdangerous((void *)(x - 1))) &&
|
||||
(LIKELY(f == (int)((x = x - sizeof(*e)) >> 16)) ||
|
||||
__asan_is_mapped(x >> 16)) &&
|
||||
!(x & (alignof(struct AsanExtra) - 1))) {
|
||||
|
@ -882,27 +895,25 @@ static size_t __asan_malloc_usable_size(const void *p) {
|
|||
}
|
||||
|
||||
int __asan_print_trace(void *p) {
|
||||
intptr_t x;
|
||||
size_t c, i, n;
|
||||
const char *name;
|
||||
struct AsanExtra *e;
|
||||
if (!(e = __asan_get_extra(p, &c))) {
|
||||
__printf(" bad pointer");
|
||||
kprintf(" bad pointer");
|
||||
return einval();
|
||||
}
|
||||
if (!__asan_read48(e->size, &n)) {
|
||||
__printf(" bad cookie");
|
||||
kprintf(" bad cookie");
|
||||
return -1;
|
||||
}
|
||||
__printf(" %,d used", n);
|
||||
kprintf(" %'zu used", n);
|
||||
if (!__asan_is_mapped((((intptr_t)p >> 3) + 0x7fff8000) >> 16)) {
|
||||
__printf(" (shadow not mapped?!)");
|
||||
kprintf(" (shadow not mapped?!)");
|
||||
}
|
||||
for (i = 0; i < ARRAYLEN(e->bt.p) && e->bt.p[i]; ++i) {
|
||||
__printf("\n%*x %s", 12, e->bt.p[i],
|
||||
weaken(__get_symbol_by_addr)
|
||||
? weaken(__get_symbol_by_addr)(e->bt.p[i])
|
||||
: "please STATIC_YOINK(\"__get_symbol_by_addr\")");
|
||||
kprintf("%n%*lx %s", 12, e->bt.p[i],
|
||||
weaken(__get_symbol_by_addr)
|
||||
? weaken(__get_symbol_by_addr)(e->bt.p[i])
|
||||
: "please STATIC_YOINK(\"__get_symbol_by_addr\")");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1078,21 +1089,36 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) {
|
|||
}
|
||||
}
|
||||
|
||||
void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) {
|
||||
struct AsanTrace tr;
|
||||
__asan_rawtrace(&tr, __builtin_frame_address(0));
|
||||
kprintf("WARNING: ASAN error during %s bad %d byte %s at %p bt %p %p %p %p%n",
|
||||
s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3]);
|
||||
}
|
||||
|
||||
void __asan_report_load(uint8_t *addr, int size) {
|
||||
if (cmpxchg(&__asan_noreentry, false, true)) {
|
||||
__asan_report_memory_fault(addr, size, "load")();
|
||||
__asan_unreachable();
|
||||
if (!__vforked) {
|
||||
__asan_report_memory_fault(addr, size, "load")();
|
||||
__asan_unreachable();
|
||||
} else {
|
||||
__asan_evil(addr, size, "vfork()", "load");
|
||||
}
|
||||
} else {
|
||||
__printf("WARNING: ASAN error reporting had an ASAN error\r\n");
|
||||
__asan_evil(addr, size, "ASAN Reporting", "load");
|
||||
}
|
||||
}
|
||||
|
||||
void __asan_report_store(uint8_t *addr, int size) {
|
||||
if (cmpxchg(&__asan_noreentry, false, true)) {
|
||||
__asan_report_memory_fault(addr, size, "store")();
|
||||
__asan_unreachable();
|
||||
if (!__vforked) {
|
||||
__asan_report_memory_fault(addr, size, "store")();
|
||||
__asan_unreachable();
|
||||
} else {
|
||||
__asan_evil(addr, size, "vfork()", "store");
|
||||
}
|
||||
} else {
|
||||
__printf("WARNING: ASAN error reporting had an ASAN error\r\n");
|
||||
__asan_evil(addr, size, "ASAN reporting", "store");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1138,12 +1164,11 @@ void __asan_install_malloc_hooks(void) {
|
|||
|
||||
void __asan_map_shadow(uintptr_t p, size_t n) {
|
||||
void *addr;
|
||||
int i, a, b;
|
||||
size_t size;
|
||||
int prot, flag;
|
||||
int i, x, a, b;
|
||||
struct DirectMap sm;
|
||||
struct MemoryIntervals *m;
|
||||
SYSDEBUG("__asan_map_shadow(0x%p, 0x%x)", p, n);
|
||||
assert(!OverlapsShadowSpace((void *)p, n));
|
||||
m = weaken(_mmi);
|
||||
a = (0x7fff8000 + (p >> 3)) >> 16;
|
||||
|
@ -1167,7 +1192,8 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
|
|||
weaken(TrackMemoryInterval)(
|
||||
m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED) == -1) {
|
||||
__asan_die("error: could not map asan shadow memory\n")();
|
||||
kprintf("error: could not map asan shadow memory%n");
|
||||
__asan_die()();
|
||||
__asan_unreachable();
|
||||
}
|
||||
__repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16),
|
||||
|
@ -1202,20 +1228,21 @@ static textstartup void __asan_shadow_string_list(char **list) {
|
|||
__asan_map_shadow((uintptr_t)list, (i + 1) * sizeof(char *));
|
||||
}
|
||||
|
||||
static textstartup void __asan_shadow_existing_mappings(void) {
|
||||
size_t i;
|
||||
struct MemoryIntervals m;
|
||||
__asan_memcpy(&m, weaken(_mmi), sizeof(m));
|
||||
for (i = 0; i < m.i; ++i) {
|
||||
__asan_map_shadow((uintptr_t)m.p[i].x << 16,
|
||||
(uintptr_t)(m.p[i].y - m.p[i].x + 1) << 16);
|
||||
static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
|
||||
size_t i) {
|
||||
uintptr_t x, y;
|
||||
if (i < m->i) {
|
||||
x = m->p[i].x;
|
||||
y = m->p[i].y;
|
||||
__asan_shadow_mapping(m, i + 1);
|
||||
__asan_map_shadow(x << 16, (y - x + 1) << 16);
|
||||
}
|
||||
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
|
||||
}
|
||||
|
||||
static textstartup bool IsMemoryManagementRuntimeLinked(void) {
|
||||
return weaken(_mmi) && weaken(sys_mmap) && weaken(MAP_ANONYMOUS) &&
|
||||
weaken(TrackMemoryInterval);
|
||||
static textstartup void __asan_shadow_existing_mappings(void) {
|
||||
__asan_shadow_mapping(&_mmi, 0);
|
||||
__asan_map_shadow(GetStackAddr(0), GetStackSize());
|
||||
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
|
||||
}
|
||||
|
||||
textstartup void __asan_init(int argc, char **argv, char **envp,
|
||||
|
@ -1223,7 +1250,7 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
|
|||
static bool once;
|
||||
if (!cmpxchg(&once, false, true)) return;
|
||||
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
||||
__write_str("error: asan binaries require windows10\n");
|
||||
__write_str("error: asan binaries require windows10\r\n");
|
||||
_Exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
|
||||
}
|
||||
REQUIRE(_mmi);
|
||||
|
@ -1241,7 +1268,7 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
|
|||
__asan_map_shadow(0, 4096);
|
||||
__asan_poison(0, PAGESIZE, kAsanNullPage);
|
||||
if (!IsWindows()) {
|
||||
__sysv_mprotect((void *)0x00007fff8000, 0x10000, PROT_READ);
|
||||
__sysv_mprotect((void *)0x7fff8000, 0x10000, PROT_READ);
|
||||
}
|
||||
__asan_shadow_string_list(argv);
|
||||
__asan_shadow_string_list(envp);
|
||||
|
|
|
@ -1,29 +1,10 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/intrin/asancodes.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
#define kAsanScale 3
|
||||
#define kAsanMagic 0x7fff8000
|
||||
#define kAsanNullPage -1 /* ∅ 0xff */
|
||||
#define kAsanProtected -2 /* P 0xfe */
|
||||
#define kAsanHeapFree -3 /* F 0xfd */
|
||||
#define kAsanHeapRelocated -4 /* R 0xfc */
|
||||
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
|
||||
#define kAsanHeapUnderrun -6 /* U 0xfa */
|
||||
#define kAsanHeapOverrun -7 /* O 0xf9 */
|
||||
#define kAsanStackUnscoped -8 /* s 0xf8 */
|
||||
#define kAsanStackOverflow -9 /* ! 0xf7 */
|
||||
#define kAsanGlobalOrder -10 /* I 0xf6 */
|
||||
#define kAsanStackFree -11 /* r 0xf5 */
|
||||
#define kAsanStackPartial -12 /* p 0xf4 */
|
||||
#define kAsanStackOverrun -13 /* o 0xf3 */
|
||||
#define kAsanStackMiddle -14 /* m 0xf2 */
|
||||
#define kAsanStackUnderrun -15 /* u 0xf1 */
|
||||
#define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
|
||||
#define kAsanUnmapped -17 /* M 0xef */
|
||||
#define kAsanGlobalRedzone -18 /* G 0xee */
|
||||
#define kAsanGlobalGone -19 /* 𝐺 0xed */
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic))
|
||||
#define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale))
|
||||
|
@ -32,7 +13,7 @@ typedef void __asan_die_f(void);
|
|||
|
||||
struct AsanFault {
|
||||
signed char kind;
|
||||
signed char *shadow;
|
||||
const signed char *shadow;
|
||||
};
|
||||
|
||||
extern bool __asan_noreentry;
|
||||
|
@ -58,4 +39,6 @@ void *__asan_memalign(size_t, size_t);
|
|||
size_t __asan_get_heap_size(const void *);
|
||||
void *__asan_realloc_in_place(void *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */
|
||||
|
|
28
libc/intrin/asancodes.h
Normal file
28
libc/intrin/asancodes.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_
|
||||
|
||||
#define kAsanScale 3
|
||||
#define kAsanMagic 0x7fff8000
|
||||
#define kAsanNullPage -1 /* ∅ 0xff */
|
||||
#define kAsanProtected -2 /* P 0xfe */
|
||||
#define kAsanHeapFree -3 /* F 0xfd */
|
||||
#define kAsanHeapRelocated -4 /* R 0xfc */
|
||||
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
|
||||
#define kAsanHeapUnderrun -6 /* U 0xfa */
|
||||
#define kAsanHeapOverrun -7 /* O 0xf9 */
|
||||
#define kAsanStackUnscoped -8 /* s 0xf8 */
|
||||
#define kAsanStackOverflow -9 /* ! 0xf7 */
|
||||
#define kAsanGlobalOrder -10 /* I 0xf6 */
|
||||
#define kAsanStackFree -11 /* r 0xf5 */
|
||||
#define kAsanStackPartial -12 /* p 0xf4 */
|
||||
#define kAsanStackOverrun -13 /* o 0xf3 */
|
||||
#define kAsanStackMiddle -14 /* m 0xf2 */
|
||||
#define kAsanStackUnderrun -15 /* u 0xf1 */
|
||||
#define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
|
||||
#define kAsanUnmapped -17 /* M 0xef */
|
||||
#define kAsanGlobalRedzone -18 /* G 0xee */
|
||||
#define kAsanGlobalGone -19 /* 𝐺 0xed */
|
||||
#define kAsanGlobalUnderrun -20 /* μ 0xec */
|
||||
#define kAsanGlobalOverrun -21 /* Ω 0xeb */
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_ */
|
42
libc/intrin/assertfail.c
Normal file
42
libc/intrin/assertfail.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Handles failure of assert() macro.
|
||||
*/
|
||||
relegated wontreturn void __assert_fail(const char *expr, const char *file,
|
||||
int line) {
|
||||
static bool noreentry;
|
||||
kprintf("%s:%d: assert(%s) failed%n", file, line, expr);
|
||||
if (cmpxchg(&noreentry, false, true)) {
|
||||
if (weaken(__die)) {
|
||||
weaken(__die)();
|
||||
} else {
|
||||
kprintf("can't backtrace b/c `__die` not linked%n");
|
||||
}
|
||||
quick_exit(23);
|
||||
}
|
||||
_Exit(24);
|
||||
}
|
|
@ -16,15 +16,15 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/nexgen32e/vendor.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
extern void(__msabi* __imp_ExitProcess)(uint32_t);
|
||||
|
||||
/**
|
||||
* Terminates process, ignoring destructors and atexit() handlers.
|
||||
*
|
|
@ -57,6 +57,12 @@ o/$(MODE)/libc/intrin/asan.o: \
|
|||
-finline \
|
||||
-finline-functions
|
||||
|
||||
o/$(MODE)/libc/intrin/kstarttsc.o \
|
||||
o/$(MODE)/libc/intrin/nomultics.o \
|
||||
o/$(MODE)/libc/intrin/ntconsolemode.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-fno-sanitize=all
|
||||
|
||||
o/$(MODE)/libc/intrin/asan.o \
|
||||
o/$(MODE)/libc/intrin/ubsan.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
|
|
798
libc/intrin/kprintf.greg.c
Normal file
798
libc/intrin/kprintf.greg.c
Normal file
|
@ -0,0 +1,798 @@
|
|||
/*-*- 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/divmod10.internal.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
#define MAXT (24 * 60 * 60 * 1000000000ull)
|
||||
#define WRAP ((MAXT + 1) / 10 * 33)
|
||||
|
||||
struct Timestamps {
|
||||
unsigned long long birth;
|
||||
unsigned long long start;
|
||||
};
|
||||
|
||||
extern int __pid;
|
||||
extern bool __replmode;
|
||||
extern bool __nomultics;
|
||||
static volatile unsigned long long kbirth;
|
||||
|
||||
privileged static struct Timestamps kenter(void) {
|
||||
struct Timestamps ts;
|
||||
ts.start = rdtsc();
|
||||
ts.birth = kbirth;
|
||||
if (!ts.birth) {
|
||||
ts.birth = kStartTsc;
|
||||
if (!ts.birth) ts.birth = 1;
|
||||
cmpxchg(&kbirth, 0, ts.birth);
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
privileged static void kleave(struct Timestamps ts) {
|
||||
uint64_t finish, elapse, adjust;
|
||||
finish = rdtsc();
|
||||
elapse = unsignedsubtract(finish, ts.start);
|
||||
adjust = ts.birth + elapse;
|
||||
if (!adjust) adjust = 1;
|
||||
cmpxchg(&kbirth, ts.birth, adjust); /* ignore overlapping time intervals */
|
||||
}
|
||||
|
||||
privileged static inline char *kadvance(char *p, char *e, long n) {
|
||||
intptr_t t = (intptr_t)p;
|
||||
if (__builtin_add_overflow(t, n, &t)) t = (intptr_t)e;
|
||||
return (char *)t;
|
||||
}
|
||||
|
||||
privileged static char *kemitquote(char *p, char *e, signed char t,
|
||||
unsigned c) {
|
||||
if (t) {
|
||||
if (p < e) {
|
||||
*p = t < 0 ? 'u' : 'L';
|
||||
}
|
||||
++p;
|
||||
}
|
||||
if (p < e) {
|
||||
*p = c;
|
||||
}
|
||||
++p;
|
||||
return p;
|
||||
}
|
||||
|
||||
privileged static unsigned long long kgetint(va_list va, signed char t,
|
||||
bool s) {
|
||||
#ifdef __LP64__
|
||||
int bits;
|
||||
unsigned long long x;
|
||||
x = va_arg(va, unsigned long);
|
||||
if (t <= 0) {
|
||||
bits = 64 - (32 >> MIN(5, -t));
|
||||
x <<= bits;
|
||||
if (s) {
|
||||
x = (signed long)x >> bits;
|
||||
} else {
|
||||
x >>= bits;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
#else
|
||||
if (s) {
|
||||
switch (t) {
|
||||
case -2:
|
||||
return (signed char)va_arg(va, int);
|
||||
case -1:
|
||||
return (signed short)va_arg(va, int);
|
||||
default:
|
||||
return va_arg(va, signed int);
|
||||
case 1:
|
||||
return va_arg(va, signed long);
|
||||
case 2:
|
||||
return va_arg(va, signed long long);
|
||||
}
|
||||
} else {
|
||||
switch (t) {
|
||||
case -2:
|
||||
return (unsigned char)va_arg(va, int);
|
||||
case -1:
|
||||
return (unsigned short)va_arg(va, int);
|
||||
default:
|
||||
return va_arg(va, unsigned int);
|
||||
case 1:
|
||||
return va_arg(va, unsigned long);
|
||||
case 2:
|
||||
return va_arg(va, unsigned long long);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
privileged static inline bool kiskernelpointer(const void *p) {
|
||||
return 0x7f0000000000 <= (intptr_t)p && (intptr_t)p < 0x800000000000;
|
||||
}
|
||||
|
||||
privileged static inline bool kistextpointer(const void *p) {
|
||||
return _base <= (const unsigned char *)p && (const unsigned char *)p < _etext;
|
||||
}
|
||||
|
||||
privileged static inline bool kisimagepointer(const void *p) {
|
||||
return _base <= (const unsigned char *)p && (const unsigned char *)p < _end;
|
||||
}
|
||||
|
||||
privileged static inline bool kischarmisaligned(const char *p, signed char t) {
|
||||
if (t == -1) return (intptr_t)p & 1;
|
||||
if (t >= 1) return !!((intptr_t)p & 3);
|
||||
return false;
|
||||
}
|
||||
|
||||
privileged static inline bool kismemtrackhosed(void) {
|
||||
return !((weaken(_mmi)->i <= weaken(_mmi)->n) &&
|
||||
(weaken(_mmi)->p == weaken(_mmi)->s ||
|
||||
weaken(_mmi)->p == (struct MemoryInterval *)kMemtrackStart));
|
||||
}
|
||||
|
||||
privileged static bool kismapped(int x) {
|
||||
size_t m, r, l = 0;
|
||||
if (!weaken(_mmi)) return true;
|
||||
if (kismemtrackhosed()) return false;
|
||||
r = weaken(_mmi)->i;
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (weaken(_mmi)->p[m].y < x) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
r = m;
|
||||
}
|
||||
}
|
||||
if (l < weaken(_mmi)->i && x >= weaken(_mmi)->p[l].x) {
|
||||
return !!(weaken(_mmi)->p[l].prot & PROT_READ);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
privileged bool kisdangerous(const void *p) {
|
||||
int frame;
|
||||
if (kisimagepointer(p)) return false;
|
||||
if (kiskernelpointer(p)) return false;
|
||||
if (IsLegalPointer(p)) {
|
||||
frame = (intptr_t)p >> 16;
|
||||
if (IsStackFrame(frame)) return false;
|
||||
if (IsOldStackFrame(frame)) return false;
|
||||
if (kismapped(frame)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
privileged static void klog(const char *b, size_t n) {
|
||||
int e;
|
||||
size_t i;
|
||||
uint16_t dx;
|
||||
uint32_t wrote;
|
||||
unsigned char al;
|
||||
long rax, rdi, rsi, rdx;
|
||||
if (IsWindows()) {
|
||||
e = __imp_GetLastError();
|
||||
__imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), b, n, &wrote, 0);
|
||||
__imp_SetLastError(e);
|
||||
} else if (IsMetal()) {
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (;;) {
|
||||
dx = 0x3F8 + UART_LSR;
|
||||
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
|
||||
if (al & UART_TTYTXR) break;
|
||||
asm("pause");
|
||||
}
|
||||
dx = 0x3F8;
|
||||
asm volatile("outb\t%0,%1"
|
||||
: /* no inputs */
|
||||
: "a"(b[i]), "dN"(dx));
|
||||
}
|
||||
} else {
|
||||
asm volatile("syscall"
|
||||
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
|
||||
: "0"(__NR_write), "1"(2), "2"(b), "3"(n)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
}
|
||||
|
||||
privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
|
||||
struct Timestamps ts) {
|
||||
int si;
|
||||
wint_t t, u;
|
||||
const char *abet;
|
||||
signed char type;
|
||||
const char *s, *f;
|
||||
unsigned long long x;
|
||||
unsigned i, j, m, rem, sign, hash, cols, prec;
|
||||
char c, *p, *e, pdot, zero, flip, dang, base, quot, z[128];
|
||||
if (kistextpointer(b) || kisdangerous(b)) n = 0;
|
||||
if (!kistextpointer(fmt)) fmt = "!!WONTFMT";
|
||||
p = b;
|
||||
f = fmt;
|
||||
e = p + n;
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
if (!(c = *f++) || c == '%') break;
|
||||
EmitFormatByte:
|
||||
if (p < e) *p = c;
|
||||
++p;
|
||||
}
|
||||
if (!c) break;
|
||||
pdot = 0;
|
||||
flip = 0;
|
||||
dang = 0;
|
||||
hash = 0;
|
||||
sign = 0;
|
||||
prec = 0;
|
||||
quot = 0;
|
||||
type = 0;
|
||||
cols = 0;
|
||||
zero = 0;
|
||||
abet = "0123456789abcdef";
|
||||
for (;;) {
|
||||
switch ((c = *f++)) {
|
||||
default:
|
||||
goto EmitFormatByte;
|
||||
case '\0':
|
||||
break;
|
||||
case '.':
|
||||
pdot = 1;
|
||||
continue;
|
||||
case '-':
|
||||
flip = 1;
|
||||
continue;
|
||||
case '#':
|
||||
hash = '0';
|
||||
continue;
|
||||
case '_':
|
||||
case ',':
|
||||
case '\'':
|
||||
quot = c;
|
||||
continue;
|
||||
case ' ':
|
||||
case '+':
|
||||
sign = c;
|
||||
continue;
|
||||
case 'h':
|
||||
--type;
|
||||
continue;
|
||||
case 'j':
|
||||
case 'l':
|
||||
case 'z':
|
||||
++type;
|
||||
continue;
|
||||
case '!':
|
||||
dang = 1;
|
||||
continue;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
si = pdot ? prec : cols;
|
||||
si *= 10;
|
||||
si += c - '0';
|
||||
goto UpdateCols;
|
||||
case '*':
|
||||
si = va_arg(va, int);
|
||||
UpdateCols:
|
||||
if (pdot) {
|
||||
if (si >= 0) {
|
||||
prec = si;
|
||||
}
|
||||
} else {
|
||||
if (si < 0) {
|
||||
flip = 1;
|
||||
si = -si;
|
||||
}
|
||||
cols = si;
|
||||
if (!cols) {
|
||||
zero = 1;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case 'T':
|
||||
x = unsignedsubtract(ts.start, ts.birth) % WRAP * 10 / 33;
|
||||
goto FormatUnsigned;
|
||||
case 'P':
|
||||
if (!__vforked) {
|
||||
x = __pid;
|
||||
} else {
|
||||
asm volatile("syscall"
|
||||
: "=a"(x)
|
||||
: "0"(__NR_getpid)
|
||||
: "rcx", "rdx", "r11", "memory", "cc");
|
||||
}
|
||||
goto FormatUnsigned;
|
||||
case 'u':
|
||||
case 'd':
|
||||
if (UNLIKELY(type <= -3)) {
|
||||
s = va_arg(va, int) ? "true" : "false";
|
||||
goto FormatString;
|
||||
}
|
||||
x = kgetint(va, type, c == 'd');
|
||||
FormatDecimal:
|
||||
if ((long long)x < 0 && c != 'u') {
|
||||
x = -x;
|
||||
sign = '-';
|
||||
}
|
||||
FormatUnsigned:
|
||||
if (x && hash) sign = hash;
|
||||
for (i = j = 0;;) {
|
||||
x = DivMod10(x, &rem);
|
||||
z[i++ & 127] = '0' + rem;
|
||||
if (pdot ? i >= prec : !x) break;
|
||||
if (quot && ++j == 3) {
|
||||
z[i++ & 127] = quot;
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
EmitNumber:
|
||||
if (flip || pdot) zero = 0;
|
||||
while (zero && sign) {
|
||||
if (p < e) *p = sign;
|
||||
if (cols) --cols;
|
||||
sign >>= 8;
|
||||
++p;
|
||||
}
|
||||
t = !!sign + !!(sign >> 8);
|
||||
if (!flip && cols >= t) {
|
||||
for (j = i; j < cols - t; ++j) {
|
||||
if (p < e) {
|
||||
*p++ = zero ? '0' : ' ';
|
||||
} else {
|
||||
p = kadvance(p, e, cols - t - j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (sign) {
|
||||
if (p < e) *p = sign;
|
||||
sign >>= 8;
|
||||
++p;
|
||||
}
|
||||
for (j = i; j; ++p) {
|
||||
--j;
|
||||
if (p < e) {
|
||||
*p = z[j & 127];
|
||||
}
|
||||
}
|
||||
if (flip && cols >= t) {
|
||||
for (j = i; j < cols - t; ++j) {
|
||||
if (p < e) {
|
||||
*p++ = ' ';
|
||||
} else {
|
||||
p = kadvance(p, e, cols - t - j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
base = 1;
|
||||
if (hash) hash = '0' | 'b' << 8;
|
||||
BinaryNumber:
|
||||
x = kgetint(va, type, false);
|
||||
FormatNumber:
|
||||
i = 0;
|
||||
m = (1 << base) - 1;
|
||||
if (hash && x) sign = hash;
|
||||
do z[i++ & 127] = abet[x & m];
|
||||
while ((x >>= base) || (pdot && i < prec));
|
||||
goto EmitNumber;
|
||||
case 'X':
|
||||
abet = "0123456789ABCDEF";
|
||||
/* fallthrough */
|
||||
case 'x':
|
||||
base = 4;
|
||||
if (hash) hash = '0' | 'x' << 8;
|
||||
goto BinaryNumber;
|
||||
case 'o':
|
||||
base = 3;
|
||||
goto BinaryNumber;
|
||||
case 'p':
|
||||
x = va_arg(va, intptr_t);
|
||||
if (!x && pdot) pdot = 0;
|
||||
if ((long)x == -1) {
|
||||
pdot = 0;
|
||||
goto FormatDecimal;
|
||||
}
|
||||
hash = '0' | 'x' << 8;
|
||||
base = 4;
|
||||
goto FormatNumber;
|
||||
case 'C':
|
||||
c = 'c';
|
||||
type = 1;
|
||||
/* fallthrough */
|
||||
case 'c':
|
||||
i = 1;
|
||||
j = 0;
|
||||
x = 0;
|
||||
s = (const char *)&x;
|
||||
t = va_arg(va, int);
|
||||
if (!type) t &= 255;
|
||||
if (hash) {
|
||||
quot = 1;
|
||||
hash = '\'';
|
||||
p = kemitquote(p, e, type, hash);
|
||||
if (cols && type) --cols; /* u/L */
|
||||
if (cols) --cols; /* start quote */
|
||||
if (cols) --cols; /* end quote */
|
||||
}
|
||||
goto EmitChar;
|
||||
case 'm':
|
||||
if (!(x = errno) && sign == ' ') {
|
||||
break;
|
||||
} else if (weaken(strerror_r) &&
|
||||
!weaken(strerror_r)(x, z, sizeof(z))) {
|
||||
s = z;
|
||||
goto FormatString;
|
||||
} else {
|
||||
goto FormatDecimal;
|
||||
}
|
||||
case 'n':
|
||||
if (__nomultics) {
|
||||
if (p < e) *p = '\r';
|
||||
++p;
|
||||
}
|
||||
if (p < e) *p = '\n';
|
||||
++p;
|
||||
break;
|
||||
case 'r':
|
||||
if (!__replmode) {
|
||||
break;
|
||||
} else {
|
||||
s = "\r\033[K";
|
||||
goto FormatString;
|
||||
}
|
||||
case 'S':
|
||||
c = 's';
|
||||
type = 1;
|
||||
/* fallthrough */
|
||||
case 's':
|
||||
if (!(s = va_arg(va, const void *))) {
|
||||
s = sign != ' ' ? "NULL" : "";
|
||||
FormatString:
|
||||
type = 0;
|
||||
hash = 0;
|
||||
} else if (!dang && (kisdangerous(s) || kischarmisaligned(s, type))) {
|
||||
if (sign == ' ') {
|
||||
if (p < e) *p = ' ';
|
||||
++p;
|
||||
}
|
||||
x = (intptr_t)s;
|
||||
base = 4;
|
||||
hash = '!' | '!' << 8;
|
||||
goto FormatNumber;
|
||||
} else if (hash) {
|
||||
quot = 1;
|
||||
hash = '"';
|
||||
if (cols && type) --cols; /* u/L */
|
||||
if (cols) --cols; /* start quote */
|
||||
if (cols) --cols; /* end quote */
|
||||
p = kemitquote(p, e, type, hash);
|
||||
}
|
||||
if (sign == ' ' && (!pdot || prec) && *s) {
|
||||
if (p < e) *p = ' ';
|
||||
++p;
|
||||
}
|
||||
for (i = j = 0; !pdot || j < prec; ++j) {
|
||||
if (UNLIKELY(!((intptr_t)s & (PAGESIZE - 1)))) {
|
||||
if (!dang && kisdangerous(s)) break;
|
||||
}
|
||||
if (!type) {
|
||||
if (!(t = *s++ & 255)) break;
|
||||
if ((t & 0300) == 0200) goto ActuallyEmitByte;
|
||||
++i;
|
||||
EmitByte:
|
||||
if (UNLIKELY(quot) && (t == '\\' || ((t == '"' && c == 's') ||
|
||||
(t == '\'' && c == 'c')))) {
|
||||
if (p + 2 <= e) {
|
||||
p[0] = '\\';
|
||||
p[1] = t;
|
||||
}
|
||||
p += 2;
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (pdot ||
|
||||
(t != 0x7F && (t >= 0x20 || (t == '\n' || t == '\t' ||
|
||||
t == '\r' || t == '\e')))) {
|
||||
ActuallyEmitByte:
|
||||
if (p < e) *p = t;
|
||||
p += 1;
|
||||
continue;
|
||||
} else if (quot) {
|
||||
if (p + 4 <= e) {
|
||||
p[0] = '\\';
|
||||
p[1] = '0' + ((t & 0300) >> 6);
|
||||
p[2] = '0' + ((t & 0070) >> 3);
|
||||
p[3] = '0' + ((t & 0007) >> 0);
|
||||
}
|
||||
p += 4;
|
||||
i += 3;
|
||||
continue;
|
||||
} else {
|
||||
/* Control Pictures
|
||||
═══════════════════════════════════════════════════════
|
||||
2400 │ 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
───────────────────────────────────────────────────────
|
||||
2400 │ ␀ ␁ ␂ ␃ ␄ ␅ ␆ ␇ ␈ ␉ ␊ ␋ ␌ ␍ ␎ ␏
|
||||
2410 │ ␐ ␑ ␒ ␓ ␔ ␕ ␖ ␗ ␘ ␙ ␚ ␛ ␜ ␝ ␞ ␟
|
||||
2420 │ ␠ ␡ ␢ ␣  ␥ ␦ */
|
||||
if (t != 0x7F) {
|
||||
t += 0x2400;
|
||||
} else {
|
||||
t = 0x2421;
|
||||
}
|
||||
goto EmitChar;
|
||||
}
|
||||
} else if (type < -1) {
|
||||
if ((t = *s++ & 255)) {
|
||||
t = kCp437[t];
|
||||
}
|
||||
} else if (type < 0) {
|
||||
t = *(const char16_t *)s;
|
||||
s += sizeof(char16_t);
|
||||
if (IsHighSurrogate(t)) {
|
||||
if (!pdot || j + 1 < prec) {
|
||||
if (UNLIKELY(!((intptr_t)s & (PAGESIZE - 1)))) {
|
||||
if (!dang && kisdangerous(s)) break;
|
||||
}
|
||||
u = *(const char16_t *)s;
|
||||
if (IsLowSurrogate(u)) {
|
||||
t = MergeUtf16(t, u);
|
||||
s += sizeof(char16_t);
|
||||
j += 1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (!t) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
t = *(const wchar_t *)s;
|
||||
s += sizeof(wchar_t);
|
||||
}
|
||||
if (!t) break;
|
||||
++i;
|
||||
EmitChar:
|
||||
if (t <= 0x7f) {
|
||||
goto EmitByte;
|
||||
} else if (t <= 0x7ff) {
|
||||
if (p + 2 <= e) {
|
||||
p[0] = 0300 | (t >> 6);
|
||||
p[1] = 0200 | (t & 077);
|
||||
}
|
||||
p += 2;
|
||||
} else if (t <= 0xffff) {
|
||||
if (UNLIKELY(IsSurrogate(t))) {
|
||||
EncodeReplacementCharacter:
|
||||
t = 0xfffd;
|
||||
}
|
||||
if (p + 3 <= e) {
|
||||
p[0] = 0340 | (t >> 12);
|
||||
p[1] = 0200 | ((t >> 6) & 077);
|
||||
p[2] = 0200 | (t & 077);
|
||||
}
|
||||
p += 3;
|
||||
} else if (~(t >> 18) & 007) {
|
||||
if (p + 4 <= e) {
|
||||
p[0] = 0360 | (t >> 18);
|
||||
p[1] = 0200 | ((t >> 12) & 077);
|
||||
p[2] = 0200 | ((t >> 6) & 077);
|
||||
p[3] = 0200 | (t & 077);
|
||||
}
|
||||
p += 4;
|
||||
} else {
|
||||
goto EncodeReplacementCharacter;
|
||||
}
|
||||
}
|
||||
if (hash) {
|
||||
if (p < e) *p = hash;
|
||||
++p;
|
||||
}
|
||||
for (; cols > i; --cols) {
|
||||
if (p < e) {
|
||||
*p++ = ' ';
|
||||
} else {
|
||||
p = kadvance(p, e, cols - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p < e) {
|
||||
*p = 0;
|
||||
} else if (e > b) {
|
||||
u = 0;
|
||||
*--e = 0;
|
||||
s = "\n...";
|
||||
if (!(((f - fmt) >= 2 && f[-2] == '\n') ||
|
||||
((f - fmt) >= 3 && f[-3] == '%' && f[-2] == 'n'))) {
|
||||
++s;
|
||||
}
|
||||
while ((t = *s++) && e > b) {
|
||||
u = *--e;
|
||||
*e = t;
|
||||
}
|
||||
if ((u & 0300) == 0200) {
|
||||
while (e > b) {
|
||||
u = *--e;
|
||||
*e = '.';
|
||||
if ((u & 0300) != 0200) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return p - b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Privileged snprintf().
|
||||
*
|
||||
* @param b is buffer, and guaranteed a NUL-terminator if `n>0`
|
||||
* @param n is number of bytes available in buffer
|
||||
* @return length of output excluding NUL, which may exceed `n`
|
||||
* @see kprintf() for documentation
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
privileged size_t ksnprintf(char *b, size_t n, const char *fmt, ...) {
|
||||
size_t m;
|
||||
va_list v;
|
||||
struct Timestamps t = {0};
|
||||
va_start(v, fmt);
|
||||
m = kformat(b, n, fmt, v, t);
|
||||
va_end(v);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Privileged vsnprintf().
|
||||
*
|
||||
* @param b is buffer, and guaranteed a NUL-terminator if `n>0`
|
||||
* @param n is number of bytes available in buffer
|
||||
* @return length of output excluding NUL, which may exceed `n`
|
||||
* @see kprintf() for documentation
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
privileged size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) {
|
||||
struct Timestamps t = {0};
|
||||
return kformat(b, n, fmt, v, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Privileged vprintf.
|
||||
*
|
||||
* @see kprintf() for documentation
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
privileged void kvprintf(const char *fmt, va_list v) {
|
||||
size_t n;
|
||||
char b[2048];
|
||||
struct Timestamps t;
|
||||
if (!v) return;
|
||||
t = kenter();
|
||||
n = kformat(b, sizeof(b), fmt, v, t);
|
||||
klog(b, MIN(n, sizeof(b)));
|
||||
kleave(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Privileged printf().
|
||||
*
|
||||
* This function is intended for crash reporting. It's designed to be as
|
||||
* unbreakable as possible, so that error messages can always be printed
|
||||
* even when the rest of the runtime is broken. As such, it has continue
|
||||
* on error semantics, doesn't support buffering between invocations and
|
||||
* floating point is not supported. Output is also truncated if the line
|
||||
* gets too long, but care is taken to preserve your newline characters.
|
||||
* Your errno and GetLastError() state will not be clobbered, and ftrace
|
||||
* and other runtime magic won't be invoked, since all the runtime magic
|
||||
* depends on this function.
|
||||
*
|
||||
* Directives:
|
||||
*
|
||||
* %[FLAGS][WIDTH|*][.[PRECISION|*]][TYPE]SPECIFIER
|
||||
*
|
||||
* Specifiers:
|
||||
*
|
||||
* - `P` pid
|
||||
* - `c` char
|
||||
* - `o` octal
|
||||
* - `b` binary
|
||||
* - `s` string
|
||||
* - `p` pointer
|
||||
* - `d` decimal
|
||||
* - `n` newline
|
||||
* - `u` unsigned
|
||||
* - `r` carriage
|
||||
* - `m` strerror
|
||||
* - `X` uppercase
|
||||
* - `T` timestamp
|
||||
* - `x` hexadecimal
|
||||
*
|
||||
* Types:
|
||||
*
|
||||
* - `hhh` bool
|
||||
* - `hh` char or cp437
|
||||
* - `h` short or char16_t
|
||||
* - `l` long or wchar_t
|
||||
* - `ll` long long
|
||||
*
|
||||
* Flags:
|
||||
*
|
||||
* - `0` zero padding
|
||||
* - `-` flip alignment
|
||||
* - `!` bypass memory safety
|
||||
* - `,` thousands grouping w/ comma
|
||||
* - `'` thousands grouping w/ apostrophe
|
||||
* - `_` thousands grouping w/ underscore
|
||||
* - `+` plus leftpad if positive (aligns w/ negatives)
|
||||
* - ` ` space leftpad if positive (aligns w/ negatives)
|
||||
* - `#` represent value with literal syntax, e.g. 0x, 0b, quotes
|
||||
*
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
privileged void kprintf(const char *fmt, ...) {
|
||||
/* system call support runtime depends on this function */
|
||||
/* function tracing runtime depends on this function */
|
||||
/* asan runtime depends on this function */
|
||||
va_list v;
|
||||
va_start(v, fmt);
|
||||
kvprintf(fmt, v);
|
||||
va_end(v);
|
||||
}
|
14
libc/intrin/kprintf.h
Normal file
14
libc/intrin/kprintf.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void kprintf(const char *, ...);
|
||||
size_t ksnprintf(char *, size_t, const char *, ...);
|
||||
void kvprintf(const char *, va_list);
|
||||
size_t kvsnprintf(char *, size_t, const char *, va_list);
|
||||
bool kisdangerous(const void *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_ */
|
26
libc/intrin/kstarttsc.c
Normal file
26
libc/intrin/kstarttsc.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
/**
|
||||
* Timestamp of process start.
|
||||
*
|
||||
* @see libc/runtime/winmain.greg.h
|
||||
* @see libc/crt/crt.S
|
||||
*/
|
||||
uint64_t kStartTsc;
|
30
libc/intrin/nomultics.c
Normal file
30
libc/intrin/nomultics.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
/**
|
||||
* Controls disablement of MULTICS newlines.
|
||||
*
|
||||
* Normally we use `\n` for newlines. If this is `true` then we'll try
|
||||
* our best to use `\r\n`. This is toggled automatically on Windows or
|
||||
* when `ioctl(TCSETS)` disables `OPOST`.
|
||||
*
|
||||
* @see kprintf()
|
||||
*/
|
||||
bool __nomultics;
|
||||
bool __replmode;
|
21
libc/intrin/ntconsolemode.c
Normal file
21
libc/intrin/ntconsolemode.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*-*- 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/runtime/internal.h"
|
||||
|
||||
uint32_t __ntconsolemode[2];
|
|
@ -1,242 +0,0 @@
|
|||
/*-*- 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/limits.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
/**
|
||||
* Privileged vprintf.
|
||||
*
|
||||
* This will work without any cosmopolitan runtime support once the
|
||||
* executable has been loaded into memory.
|
||||
*/
|
||||
privileged noasan noubsan noinstrument void __vprintf(const char *fmt,
|
||||
va_list va) {
|
||||
short w[2];
|
||||
uint16_t dx;
|
||||
const void *s;
|
||||
uint32_t wrote;
|
||||
unsigned long x;
|
||||
unsigned char al;
|
||||
int i, j, t, cstr;
|
||||
long d, rax, rdi, rsi, rdx, dot;
|
||||
char c, *p, *e, pad, bits, base, sign, thou, z[28], b[2048];
|
||||
p = b;
|
||||
e = p + sizeof(b);
|
||||
do {
|
||||
switch ((c = *fmt++)) {
|
||||
default:
|
||||
if (p < e) {
|
||||
*p++ = c;
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
case '%':
|
||||
dot = 0;
|
||||
pad = ' ';
|
||||
sign = 0;
|
||||
bits = 0;
|
||||
thou = 0;
|
||||
w[0] = 0;
|
||||
w[1] = SHRT_MAX;
|
||||
NeedMoar:
|
||||
switch ((c = *fmt++)) {
|
||||
case '\0':
|
||||
break;
|
||||
case 'l':
|
||||
case 'z':
|
||||
goto NeedMoar;
|
||||
case ' ':
|
||||
case '+':
|
||||
sign = c;
|
||||
goto NeedMoar;
|
||||
case 'e':
|
||||
dot = 1;
|
||||
goto NeedMoar;
|
||||
case ',':
|
||||
thou = c;
|
||||
goto NeedMoar;
|
||||
case 'h':
|
||||
bits = 16;
|
||||
goto NeedMoar;
|
||||
case '0':
|
||||
pad = c;
|
||||
/* fallthrough */
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
w[dot] *= 10;
|
||||
w[dot] += c - '0';
|
||||
goto NeedMoar;
|
||||
case '*':
|
||||
w[dot] = va_arg(va, int);
|
||||
goto NeedMoar;
|
||||
case 'd':
|
||||
d = va_arg(va, long);
|
||||
ApiAbuse:
|
||||
x = d;
|
||||
if (d < 0) {
|
||||
x = -x;
|
||||
sign = '-';
|
||||
}
|
||||
for (i = j = 0;;) {
|
||||
z[i++] = x % 10 + '0';
|
||||
if (!(x /= 10)) break;
|
||||
if (thou && !(++j % 3)) {
|
||||
z[i++] = thou;
|
||||
}
|
||||
}
|
||||
if (sign) {
|
||||
z[i++] = sign;
|
||||
}
|
||||
EmitNumber:
|
||||
while (w[0]-- > i) {
|
||||
if (p < e) *p++ = pad;
|
||||
}
|
||||
do {
|
||||
if (p < e) *p++ = z[--i];
|
||||
} while (i);
|
||||
break;
|
||||
case 'b':
|
||||
base = 1;
|
||||
BinaryNumber:
|
||||
i = 0;
|
||||
x = va_arg(va, unsigned long);
|
||||
do z[i++] = "0123456789abcdef"[x & ((1 << base) - 1)];
|
||||
while ((x >>= base) && i < w[1]);
|
||||
goto EmitNumber;
|
||||
case 'p':
|
||||
pad = '0';
|
||||
w[0] = 12;
|
||||
w[1] = 12;
|
||||
/* fallthrough */
|
||||
case 'x':
|
||||
base = 4;
|
||||
goto BinaryNumber;
|
||||
case 'o':
|
||||
base = 3;
|
||||
goto BinaryNumber;
|
||||
case 'c':
|
||||
cstr = va_arg(va, int);
|
||||
s = &cstr;
|
||||
goto EmitString;
|
||||
case 's':
|
||||
s = va_arg(va, const void *);
|
||||
EmitString:
|
||||
if (!s) {
|
||||
s = "NULL";
|
||||
bits = 0;
|
||||
} else if ((uintptr_t)s < PAGESIZE) {
|
||||
d = (intptr_t)s;
|
||||
goto ApiAbuse;
|
||||
}
|
||||
for (i = 0; i < w[1]; ++i) {
|
||||
if (!bits) {
|
||||
t = ((const char *)s)[i];
|
||||
EmitByte:
|
||||
if (t) {
|
||||
if (p < e) {
|
||||
*p++ = t;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
t = ((const char16_t *)s)[i];
|
||||
if (t <= 0x7f) {
|
||||
goto EmitByte;
|
||||
} else if (t <= 0x7ff) {
|
||||
if (p + 1 < e) {
|
||||
p[0] = 0300 | t >> 6;
|
||||
p[1] = 0200 | x << 8 | t & 077;
|
||||
p += 2;
|
||||
}
|
||||
} else if (p + 2 < e) {
|
||||
p[0] = 0340 | t >> 12;
|
||||
p[1] = 0200 | x << 8 | (t >> 6) & 077;
|
||||
p[2] = 0200 | x << 8 | t & 077;
|
||||
p += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (w[0]-- > i) {
|
||||
if (p < e) *p++ = pad;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (c);
|
||||
if (p == e) {
|
||||
e[-4] = '.';
|
||||
e[-3] = '.';
|
||||
e[-2] = '.';
|
||||
e[-1] = '\n';
|
||||
}
|
||||
if (IsWindows()) {
|
||||
WriteFile(GetStdHandle(kNtStdErrorHandle), b, p - b, &wrote, 0);
|
||||
} else if (IsMetal()) {
|
||||
for (e = p, p = b; p < e; ++p) {
|
||||
for (;;) {
|
||||
dx = 0x3F8 + UART_LSR;
|
||||
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
|
||||
if (al & UART_TTYTXR) break;
|
||||
asm("pause");
|
||||
}
|
||||
dx = 0x3F8;
|
||||
asm volatile("outb\t%0,%1"
|
||||
: /* no inputs */
|
||||
: "a"(*p), "dN"(dx));
|
||||
}
|
||||
} else {
|
||||
asm volatile("syscall"
|
||||
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
|
||||
: "0"(__NR_write), "1"(2L), "2"(b), "3"(p - b)
|
||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Privileged printf.
|
||||
*
|
||||
* This will work without any cosmopolitan runtime support once the
|
||||
* executable has been loaded into memory.
|
||||
*/
|
||||
privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
|
||||
/* system call support runtime depends on this function */
|
||||
/* function tracing runtime depends on this function */
|
||||
/* asan runtime depends on this function */
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
__vprintf(fmt, va);
|
||||
va_end(va);
|
||||
}
|
50
libc/intrin/quick_exit.c
Normal file
50
libc/intrin/quick_exit.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*-*- 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/bits/weaken.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle};
|
||||
|
||||
/**
|
||||
* Exits process faster.
|
||||
*
|
||||
* @param exitcode is masked with 255
|
||||
* @noreturn
|
||||
*/
|
||||
wontreturn void quick_exit(int exitcode) {
|
||||
int i;
|
||||
const uintptr_t *p;
|
||||
if (weaken(fflush)) {
|
||||
weaken(fflush)(0);
|
||||
}
|
||||
if (SupportsWindows() && __ntconsolemode[0]) {
|
||||
for (i = 0; i < 2; ++i) {
|
||||
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
|
||||
}
|
||||
}
|
||||
for (p = __fini_array_end; p > __fini_array_start;) {
|
||||
((void (*)(void))(*--p))();
|
||||
}
|
||||
_Exit(exitcode);
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
|
@ -189,7 +190,7 @@ static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t x) {
|
|||
|
||||
void __ubsan_abort(const struct UbsanSourceLocation *loc,
|
||||
const char *description) {
|
||||
__printf("\r\n%s:%d: ubsan error: %s\r\n", loc->file, loc->line, description);
|
||||
kprintf("%n%s:%d: ubsan error: %s%n", loc->file, loc->line, description);
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
_Exit(134);
|
||||
}
|
||||
|
@ -258,7 +259,7 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
|
|||
p = __stpcpy(p, " align ");
|
||||
p = __intcpy(p, info->alignment);
|
||||
} else {
|
||||
p = __stpcpy(p, "insufficient size\r\n\t");
|
||||
p = __stpcpy(p, "insufficient size%n\t");
|
||||
p = __stpcpy(p, kind);
|
||||
p = __stpcpy(p, " address 0x");
|
||||
p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
|
||||
|
|
21
libc/intrin/vforked.c
Normal file
21
libc/intrin/vforked.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*-*- 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/calls/internal.h"
|
||||
|
||||
int __vforked;
|
Loading…
Add table
Add a link
Reference in a new issue