Make numerous improvements

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

View file

@ -26,7 +26,7 @@
textwindows wontreturn void sys_abort_nt(void) {
int rva;
siginfo_t info;
memset(&info, 0, sizeof(info));
bzero(&info, sizeof(info));
info.si_signo = SIGABRT;
rva = __sighandrvas[SIGABRT];
if (rva >= kSigactionMinRva) {

View file

@ -17,17 +17,22 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
int i;
for (i = 0; i < mm->i; ++i) {
if (mm->p[i].y < mm->p[i].x) return false;
if (mm->p[i].y < mm->p[i].x) {
return false;
}
if (i) {
if (mm->p[i].h || mm->p[i - 1].h) {
if (mm->p[i].x <= mm->p[i - 1].y) return false;
if (mm->p[i].h != -1 || mm->p[i - 1].h != -1) {
if (mm->p[i].x <= mm->p[i - 1].y) {
return false;
}
} else {
if (mm->p[i].x <= mm->p[i - 1].y + 1) return false;
if (!(mm->p[i - 1].y + 1 <= mm->p[i].x)) {
return false;
}
}
}
}

View file

@ -19,81 +19,23 @@
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/dce.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/nr.h"
static noasan size_t __assert_strlen(const char *s) {
size_t i = 0;
while (s[i]) ++i;
return i;
}
static noasan char *__assert_stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
if (!(d[i] = s[i])) {
return d + i;
}
}
}
static privileged noinline noasan wontreturn void __assert_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static privileged noinline noasan ssize_t __assert_write(const void *data,
size_t size) {
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
}
}
/**
* Handles failure of assert() macro.
*/
relegated wontreturn noasan void __assert_fail(const char *expr,
const char *file, int line) {
static bool once;
char *msg, *p, linebuf[16];
unsigned i, exprlen, filelen;
if (cmpxchg(&once, false, true)) {
exprlen = expr ? __assert_strlen(expr) : 0;
filelen = file ? __assert_strlen(file) : 0;
p = msg = alloca(MIN(512, exprlen + filelen + 64));
p = __assert_stpcpy(p, file);
p = __assert_stpcpy(p, ":");
if (line < 1) line = 1;
for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10;
while (i) *p++ = linebuf[--i];
p = __assert_stpcpy(p, ": assert(");
p = __assert_stpcpy(p, expr);
p = __assert_stpcpy(p, ")\r\n");
__assert_write(msg, p - msg);
if (weaken(__die)) weaken(__die)();
relegated wontreturn void __assert_fail(const char *expr, const char *file,
int line) {
static bool noreentry;
__printf("%s:%d: assert(%s) failed\r\n", file, line, expr);
if (cmpxchg(&noreentry, false, true)) {
if (weaken(__die)) {
weaken(__die)();
} else {
__printf("can't backtrace b/c `__die` not linked\r\n");
}
exit(23);
}
__assert_exit(23);
_exit(24);
}

View file

@ -1,11 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_CARSORT_H_
#define COSMOPOLITAN_LIBC_RUNTIME_CARSORT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void carsort100(size_t, int32_t (*)[2]) paramsnonnull() nocallback nothrow;
void carsort1000(size_t, int32_t (*)[2]) paramsnonnull() nocallback nothrow;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_CARSORT_H_ */

View file

@ -1,40 +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 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/runtime/carsort.h"
#include "libc/str/str.h"
/**
* Sorts int32 key-value arrays of trivial size.
*
* @see test/libc/alg/carsort_test.c
* @see carsort1000() if larger
*/
textstartup void carsort100(size_t n, int32_t a[n][2]) {
int32_t t[2];
unsigned i, j;
for (i = 1; i < n; ++i) {
j = i;
memcpy(t, a[i], sizeof(t));
while (j > 0 && t[0] < a[j - 1][0]) {
memcpy(a[j], a[j - 1], sizeof(t));
--j;
}
memcpy(a[j], t, sizeof(t));
}
}

View file

@ -1,60 +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 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/runtime/carsort.h"
#include "libc/str/str.h"
static textstartup size_t HeapSortMax(size_t n, int32_t A[n][2], long i, long j,
long k) {
if (j < n && A[j][0] > A[i][0]) i = j;
if (k < n && A[k][0] > A[i][0]) i = k;
return i;
}
static textstartup void HeapSortDown(size_t n, int32_t A[n][2], long i) {
size_t j;
int32_t t[2];
for (;;) {
j = HeapSortMax(n, A, i, 2 * i + 1, 2 * i + 2);
if (j == i) break;
memcpy(t, A[i], sizeof(t));
memcpy(A[i], A[j], sizeof(t));
memcpy(A[j], t, sizeof(t));
i = j;
}
}
/**
* Sorts int32 key-value arrays of nontrivial size.
*
* @see test/libc/alg/carsort_test.c
* @see carsort100() if smaller
*/
textstartup void carsort1000(size_t n, int32_t A[n][2]) {
size_t i;
int32_t t[2];
for (i = ((n - 2) / 2) + 1; i > 0; i--) {
HeapSortDown(n, A, i - 1);
}
for (i = 0; i < n; i++) {
memcpy(t, A[n - i - 1], sizeof(t));
memcpy(A[n - i - 1], A[0], sizeof(t));
memcpy(A[0], t, sizeof(t));
HeapSortDown(n - i - 1, A, 0);
}
}

View file

@ -17,8 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/runtime/ezmap.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
/**
@ -26,14 +24,9 @@
* @return 0 on success or -1 on system error
*/
int CloseSymbolTable(struct SymbolTable **table) {
int rc;
struct SymbolTable *t;
rc = 0;
if (*table && *table != MAP_FAILED) {
t = *table;
*table = NULL;
rc |= UnmapFile(&t->mf);
rc |= munmap(t, t->scratch);
}
return rc;
if (!*table) return 0;
t = *table;
*table = 0;
return munmap(t, t->mapsize);
}

View file

@ -59,8 +59,7 @@ cosmo: push %rbp
pop %rax
add $8,%rax
jmp 1b
2: nop
call .Largs
2: call .Largs
.weak main
call main
xchg %eax,%edi

View file

@ -51,9 +51,10 @@ static struct CxaAtexitBlocks {
* @return 0 on success or nonzero w/ errno
* @note folks have forked libc in past just to unbloat atexit()
*/
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
int __cxa_atexit(void *fp, void *arg, void *pred) {
unsigned i;
struct CxaAtexitBlock *b, *b2;
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
b = __cxa_blocks.p;
if (!b) b = __cxa_blocks.p = &__cxa_blocks.root;
if (!~b->mask) {
@ -83,9 +84,8 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
*
* @param pred can be null to match all
*/
noasan void __cxa_finalize(void *pred) {
unsigned i;
unsigned long mask;
void __cxa_finalize(void *pred) {
unsigned i, mask;
struct CxaAtexitBlock *b, *b2;
StartOver:
if ((b = __cxa_blocks.p)) {

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
@ -41,12 +42,18 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
* combination of flags, that'll cause Windows to actually do this!
*/
upsize = ROUNDUP(size, FRAMESIZE);
if ((dm.maphandle = CreateFileMappingNuma(
-1, &kNtIsInheritable, kNtPageExecuteReadwrite, upsize >> 32,
upsize, NULL, kNtNumaNoPreferredNode))) {
if ((dm.addr = MapViewOfFileExNuma(
dm.maphandle, kNtFileMapWrite | kNtFileMapExecute, 0, 0, upsize,
addr, kNtNumaNoPreferredNode))) {
dm.maphandle = CreateFileMappingNuma(-1, &kNtIsInheritable,
kNtPageExecuteReadwrite, upsize >> 32,
upsize, NULL, kNtNumaNoPreferredNode);
SYSDEBUG("CreateFileMappingNuma(-1, kNtPageExecuteReadwrite, 0x%x/0x%x) -> "
"0x%x",
upsize, size, dm.maphandle);
if (dm.maphandle) {
dm.addr =
MapViewOfFileExNuma(dm.maphandle, kNtFileMapWrite | kNtFileMapExecute,
0, 0, upsize, addr, kNtNumaNoPreferredNode);
SYSDEBUG("MapViewOfFileExNuma(WX, 0x%x) -> addr:0x%x", addr, dm.addr);
if (dm.addr) {
for (i = 0; i < size; i += got) {
got = 0;
op.Internal = 0;
@ -65,16 +72,26 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
CloseHandle(dm.maphandle);
}
} else {
if ((dm.maphandle = CreateFileMappingNuma(
handle, &kNtIsInheritable,
(prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead,
handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL,
kNtNumaNoPreferredNode))) {
if ((dm.addr = MapViewOfFileExNuma(
dm.maphandle,
(prot & PROT_WRITE) ? kNtFileMapWrite | kNtFileMapExecute
: kNtFileMapRead | kNtFileMapExecute,
off >> 32, off, size, addr, kNtNumaNoPreferredNode))) {
dm.maphandle = CreateFileMappingNuma(
handle, &kNtIsInheritable,
(prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead,
handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL,
kNtNumaNoPreferredNode);
SYSDEBUG("CreateFileMappingNuma(fhand:%d, prot:%s, size:0x%x) -> "
"handle:0x%x",
handle, (prot & PROT_WRITE) ? "XRW" : "XR",
handle != -1 ? 0 : size);
if (dm.maphandle) {
dm.addr = MapViewOfFileExNuma(
dm.maphandle,
(prot & PROT_WRITE) ? kNtFileMapWrite | kNtFileMapExecute
: kNtFileMapRead | kNtFileMapExecute,
off >> 32, off, size, addr, kNtNumaNoPreferredNode);
SYSDEBUG(
"MapViewOfFileExNuma(prot:%s, off:0x%x, size:0x%x, addr:0x%x) -> "
"addr:0x%x",
(prot & PROT_WRITE) ? "WX" : "RX", off, size, addr);
if (dm.addr) {
return dm;
} else {
CloseHandle(dm.maphandle);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/directmap.internal.h"
@ -30,9 +31,13 @@
*/
noasan struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags,
int fd, int64_t off) {
struct DirectMap dm;
if (!IsWindows() && !IsMetal()) {
return (struct DirectMap){__sys_mmap(addr, size, prot, flags, fd, off, off),
kNtInvalidHandleValue};
dm.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
SYSDEBUG("sys_mmap(0x%x, 0x%x, %d, 0x%x, %d, %d) -> 0x%x", addr, size, prot,
flags, fd, off, dm.addr);
dm.maphandle = kNtInvalidHandleValue;
return dm;
} else if (IsMetal()) {
return sys_mmap_metal(addr, size, prot, flags, fd, off);
} else {

View file

@ -19,6 +19,7 @@
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/ezmap.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"

View file

@ -1,34 +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 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/runtime/memtrack.internal.h"
noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
unsigned l, m, r;
l = 0;
r = mm->i;
while (l < r) {
m = (l + r) >> 1;
if (mm->p[m].y < x) {
l = m + 1;
} else {
r = m;
}
}
return l;
}

View file

@ -21,6 +21,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/ntspawn.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/fmt/itoa.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/nt2sysv.h"
@ -41,57 +42,13 @@
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
static textwindows noasan void NtDebug(const char *fmt, ...) {
return;
int i;
va_list va;
uint32_t w, u;
const char *s;
unsigned long d;
char c, b[256], *p;
va_start(va, fmt);
for (p = b;;) {
switch ((c = *fmt++)) {
case '\0':
va_end(va);
WriteFile(GetStdHandle(kNtStdErrorHandle), b, p - b, &w, 0);
return;
case '%':
switch ((c = *fmt++)) {
case 's':
for (s = va_arg(va, const char *); s && *s;) *p++ = *s++;
break;
case 'd':
d = va_arg(va, unsigned long);
for (i = 16; i--;) {
u = (d >> (i * 4)) & 0xf;
if (u < 10) {
c = '0' + u;
} else {
u -= 10;
c = 'a' + u;
}
*p++ = c;
}
break;
default:
*p++ = c;
break;
}
break;
default:
*p++ = c;
break;
}
}
}
static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) {
*x = 0;
while (*p == ' ') p++;
@ -118,18 +75,18 @@ static noinline textwindows noasan bool ForkIo(int64_t h, void *buf, size_t n,
static noinline textwindows noasan void WriteAll(int64_t h, void *buf,
size_t n) {
if (!ForkIo(h, buf, n, WriteFile)) {
NtDebug("fork() WriteFile(%zu) failed %d\n", n, GetLastError());
SYSDEBUG("fork() WriteFile(%zu) failed %d\n", n, GetLastError());
}
}
static textwindows noinline noasan void ReadAll(int64_t h, void *buf,
size_t n) {
if (!ForkIo(h, buf, n, ReadFile)) {
NtDebug("fork() ReadFile(%zu) failed %d\n", n, GetLastError());
SYSDEBUG("fork() ReadFile(%zu) failed %d\n", n, GetLastError());
}
}
textwindows noasan void WinMainForked(void) {
textwindows noasan noinstrument void WinMainForked(void) {
void *addr;
jmp_buf jb;
long mapcount;
@ -180,7 +137,6 @@ textwindows noasan void WinMainForked(void) {
textwindows int sys_fork_nt(void) {
jmp_buf jb;
char exe[PATH_MAX];
int64_t reader, writer;
int i, rc, pid, releaseme;
char *p, forkvar[6 + 21 + 1 + 21 + 1];
@ -190,18 +146,17 @@ textwindows int sys_fork_nt(void) {
if (!setjmp(jb)) {
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
p = stpcpy(forkvar, "_FORK=");
p += uint64toarray_radix10(reader, p);
*p++ = ' ';
p += uint64toarray_radix10(reader, p), *p++ = ' ';
p += uint64toarray_radix10(writer, p);
memset(&startinfo, 0, sizeof(startinfo));
bzero(&startinfo, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles;
startinfo.hStdInput = g_fds.p[0].handle;
startinfo.hStdOutput = g_fds.p[1].handle;
startinfo.hStdError = g_fds.p[2].handle;
GetModuleFileNameA(0, exe, ARRAYLEN(exe));
if (ntspawn(exe, __argv, environ, forkvar, &kNtIsInheritable, NULL, true,
0, NULL, &startinfo, &procinfo) != -1) {
if (ntspawn((char *)getauxval(AT_EXECFN), __argv, environ, forkvar,
&kNtIsInheritable, NULL, true, 0, NULL, &startinfo,
&procinfo) != -1) {
CloseHandle(reader);
CloseHandle(procinfo.hThread);
if (weaken(__sighandrvas) &&

View file

@ -16,31 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/bisectcarleft.internal.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/repmovsb.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/rdtscp.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sig.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
#pragma weak stderr
#define MAX_NESTING 512
/**
* @fileoverview Plain-text function call logging.
@ -52,19 +43,26 @@
void ftrace_hook(void);
static int noreentry;
static int g_skew;
static int g_lastsymbol;
static uint64_t laststamp;
static char g_buf[512];
static const char *g_lastsymbol;
static struct SymbolTable *g_symbols;
static noasan int GetNestingLevel(struct StackFrame *frame) {
forceinline int GetNestingLevelImpl(struct StackFrame *frame) {
int nesting = -2;
while (frame) {
++nesting;
frame = frame->next;
}
return max(0, nesting);
return MAX(0, nesting);
}
forceinline int GetNestingLevel(struct StackFrame *frame) {
int nesting;
nesting = GetNestingLevelImpl(frame);
if (nesting < g_skew) g_skew = nesting;
nesting -= g_skew;
return MIN(MAX_NESTING, nesting);
}
/**
@ -74,41 +72,22 @@ static noasan int GetNestingLevel(struct StackFrame *frame) {
* prologues of other functions. We assume those functions behave
* according to the System Five NexGen32e ABI.
*/
privileged noasan void ftracer(void) {
char *p;
privileged noinstrument noasan void ftracer(void) {
int symbol;
uint64_t stamp;
const char *symbol;
static bool noreentry;
struct StackFrame *frame;
size_t nesting, symbolsize;
if (!cmpxchg(&noreentry, 0, 1)) return;
if (g_symbols) {
stamp = rdtsc();
frame = __builtin_frame_address(0);
frame = frame->next;
symbol =
&g_symbols->name_base[g_symbols
->symbols[bisectcarleft(
(const int32_t(*)[2])g_symbols->symbols,
g_symbols->count,
frame->addr - g_symbols->addr_base)]
.name_rva];
if (symbol != g_lastsymbol) {
symbolsize = strlen(symbol);
nesting = GetNestingLevel(frame);
if (2 + nesting * 2 + symbolsize + 1 + 21 + 2 <= ARRAYLEN(g_buf)) {
p = g_buf;
*p++ = '+';
*p++ = ' ';
memset(p, ' ', nesting * 2);
p += nesting * 2;
p = mempcpy(p, symbol, symbolsize);
*p++ = ' ';
p += uint64toarray_radix10((stamp - laststamp) / 3.3, p);
*p++ = '\r';
*p++ = '\n';
write(2, g_buf, p - g_buf);
}
if ((symbol = GetSymbol(g_symbols, frame->addr)) != -1 &&
symbol != g_lastsymbol) {
g_lastsymbol = symbol;
__printf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "",
GetSymbolName(g_symbols, symbol),
(long)(unsignedsubtract(stamp, laststamp) / 3.3));
laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
}
}
@ -116,9 +95,17 @@ privileged noasan void ftracer(void) {
}
textstartup void ftrace_install(void) {
if ((g_symbols = OpenSymbolTable(FindDebugBinary()))) {
__hook(ftrace_hook, g_symbols);
const char *path;
if ((path = FindDebugBinary())) {
if ((g_symbols = OpenSymbolTable(path))) {
laststamp = kStartTsc;
g_lastsymbol = -1;
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
__hook(ftrace_hook, g_symbols);
} else {
__printf("error: --ftrace failed to open symbol table\r\n");
}
} else {
write(2, "error: --ftrace needs the concomitant .com.dbg binary\n", 54);
__printf("error: --ftrace needs concomitant .com.dbg binary\r\n");
}
}

View file

@ -21,8 +21,9 @@
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
static textwindows noasan axdx_t Recode16to8(char *dst, size_t dstsize,
const char16_t *src) {
static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
size_t dstsize,
const char16_t *src) {
axdx_t r;
uint64_t w;
wint_t x, y;
@ -30,15 +31,14 @@ static textwindows noasan axdx_t Recode16to8(char *dst, size_t dstsize,
if (!(x = src[r.dx++])) break;
if (IsUtf16Cont(x)) continue;
if (!IsUcs2(x)) {
if (!(y = src[r.dx++])) break;
y = src[r.dx++];
x = MergeUtf16(x, y);
}
for (w = tpenc(x); w && r.ax + 1 < dstsize; w >>= 8) {
dst[r.ax++] = w & 0xFF;
}
}
if (r.ax < dstsize) {
dst[r.ax] = 0;
w = tpenc(x);
do {
if (r.ax + 1 >= dstsize) break;
dst[r.ax++] = w;
} while ((w >>= 8));
}
return r;
}
@ -53,22 +53,19 @@ static textwindows noasan axdx_t Recode16to8(char *dst, size_t dstsize,
* @param max is the pointer count capacity of envp
* @return number of variables decoded, excluding NULL-terminator
*/
textwindows noasan int GetDosEnviron(const char16_t *env, char *buf,
size_t size, char **envp, size_t max) {
textwindows noasan noinstrument int GetDosEnviron(const char16_t *env,
char *buf, size_t size,
char **envp, size_t max) {
int i;
axdx_t r;
i = 0;
if (size) {
--size;
while (*env) {
if (i + 1 < max) envp[i++] = buf;
r = Recode16to8(buf, size, env);
size -= r.ax + 1;
buf += r.ax + 1;
env += r.dx;
}
*buf = '\0';
--size;
while (*env) {
if (i + 1 < max) envp[i++] = buf;
r = Recode16to8(buf, size, env);
size -= r.ax + 1;
buf += r.ax + 1;
env += r.dx;
}
if (i < max) envp[i] = NULL;
return i;
}

View file

@ -52,7 +52,7 @@ bool __grow(void *pp, size_t *capacity, size_t itemsize, size_t extra) {
!__builtin_mul_overflow(n2, itemsize, &t2)) {
if (weaken(realloc) && (p2 = weaken(realloc)(p1, ROUNDUP(t2, 32)))) {
if (!p1 && *p) memcpy(p2, *p, t1);
memset((char *)p2 + t1, 0, t2 - t1);
bzero((char *)p2 + t1, t2 - t1);
*capacity = n2;
*p = p2;
return true;

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigset.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/sysv/consts/prot.h"
@ -43,37 +44,37 @@
*
* @see ape/ape.lds
*/
privileged void __hook(void *ifunc, struct SymbolTable *symbols) {
privileged noinstrument noasan void __hook(void *ifunc,
struct SymbolTable *symbols) {
size_t i;
char *p, *pe;
intptr_t addr;
uint64_t code, mcode;
unsigned char *p, *pe;
sigset_t mask, oldmask;
const intptr_t kMcount = (intptr_t)&mcount;
const intptr_t kProgramCodeStart = (intptr_t)&_ereal;
const intptr_t kPrivilegedStart = (intptr_t)&__privileged_start;
const bool kIsBinaryAligned = !(kPrivilegedStart & (PAGESIZE - 1));
intptr_t kMcount = (intptr_t)&mcount;
intptr_t kProgramCodeStart = (intptr_t)&_ereal;
intptr_t kPrivilegedStart = (intptr_t)&__privileged_start;
bool kIsBinaryAligned = !(kPrivilegedStart & (PAGESIZE - 1));
sigfillset(&mask);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
if (mprotect((void *)symbols->addr_base,
kPrivilegedStart - symbols->addr_base,
kIsBinaryAligned ? PROT_READ | PROT_WRITE
: PROT_READ | PROT_WRITE | PROT_EXEC) != -1) {
for (i = 0; i < symbols->count - 1; ++i) {
if (symbols->addr_base + symbols->symbols[i].addr_rva <
kProgramCodeStart) {
continue; /* skip over real mode symbols */
for (i = 0; i < symbols->count; ++i) {
if (symbols->addr_base + symbols->symbols[i].x < kProgramCodeStart) {
continue;
}
if (symbols->addr_base + symbols->symbols[i].addr_rva >=
kPrivilegedStart) {
break; /* stop before privileged symbols */
if (symbols->addr_base + symbols->symbols[i].y >= kPrivilegedStart) {
break;
}
for (p = (unsigned char *)(symbols->addr_base +
symbols->symbols[i].addr_rva),
pe = (unsigned char *)(symbols->addr_base +
symbols->symbols[i + 1].addr_rva);
p < pe - 8; ++p) {
code = READ64LE(p);
for (p = (char *)symbols->addr_base + symbols->symbols[i].x,
pe = (char *)symbols->addr_base + symbols->symbols[i].y;
p + 8 - 1 <= pe; ++p) {
code = ((uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 |
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000);
/*
* Test for -mrecord-mcount (w/ -fpie or -fpic)
@ -95,10 +96,10 @@ privileged void __hook(void *ifunc, struct SymbolTable *symbols) {
p[0] = 0x67;
p[1] = 0xE8;
addr = (intptr_t)ifunc - ((intptr_t)&p[2] + 4);
p[2] = addr >> 000;
p[3] = addr >> 010;
p[4] = addr >> 020;
p[5] = addr >> 030;
p[2] = (addr & 0x000000ff) >> 000;
p[3] = (addr & 0x0000ff00) >> 010;
p[4] = (addr & 0x00ff0000) >> 020;
p[5] = (addr & 0xff000000) >> 030;
break;
}
@ -111,10 +112,10 @@ privileged void __hook(void *ifunc, struct SymbolTable *symbols) {
if (p[-1] != 0x66 /* nopw 0x0(%rax,%rax,1) [donotwant] */) {
p[0] = 0xE8 /* call Jvds */;
addr = (intptr_t)ifunc - ((intptr_t)&p[1] + 4);
p[1] = addr >> 000;
p[2] = addr >> 010;
p[3] = addr >> 020;
p[4] = addr >> 030;
p[1] = (addr & 0x000000ff) >> 000;
p[2] = (addr & 0x0000ff00) >> 010;
p[3] = (addr & 0x00ff0000) >> 020;
p[4] = (addr & 0xff000000) >> 030;
}
break;
}

View file

@ -26,7 +26,7 @@
* @assume stack addresses are always greater than heap addresses
* @assume stack memory isn't stored beneath %rsp (-mno-red-zone)
*/
bool _isheap(void *p) {
noasan bool _isheap(void *p) {
int x, i;
uintptr_t rsp;
asm("mov\t%%rsp,%0" : "=r"(rsp));

View file

@ -16,10 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
/**
* Helper function for allocating anonymous mapping.
@ -31,7 +35,17 @@
*
* Except it offers a small saving on code size.
*/
void *mapanon(size_t mapsize) {
return mmap(NULL, mapsize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
void *mapanon(size_t size) {
void *m;
if (!size || bsrl(size) >= 40) {
errno = EINVAL;
return MAP_FAILED;
}
m = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (m == MAP_FAILED) {
if (weaken(__oom_hook)) {
weaken(__oom_hook)(size);
}
}
return m;
}

View file

@ -19,183 +19,123 @@
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
static noasan void *MoveMemoryNoAsan(void *dst, const void *src, size_t n) {
size_t i;
xmm_t v, w;
char *d, *r;
const char *s;
uint64_t a, b;
d = dst;
s = src;
switch (n) {
case 9 ... 15:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(&b, s + n - 8, 8);
__builtin_memcpy(d, &a, 8);
__builtin_memcpy(d + n - 8, &b, 8);
return d;
case 5 ... 7:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(&b, s + n - 4, 4);
__builtin_memcpy(d, &a, 4);
__builtin_memcpy(d + n - 4, &b, 4);
return d;
case 17 ... 32:
__builtin_memcpy(&v, s, 16);
__builtin_memcpy(&w, s + n - 16, 16);
__builtin_memcpy(d, &v, 16);
__builtin_memcpy(d + n - 16, &w, 16);
return d;
case 16:
__builtin_memcpy(&v, s, 16);
__builtin_memcpy(d, &v, 16);
return d;
case 0:
return d;
case 1:
*d = *s;
return d;
case 8:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(d, &a, 8);
return d;
case 4:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(d, &a, 4);
return d;
case 2:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(d, &a, 2);
return d;
case 3:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(&b, s + 1, 2);
__builtin_memcpy(d, &a, 2);
__builtin_memcpy(d + 1, &b, 2);
return d;
default:
r = d;
if (d > s) {
do {
n -= 32;
__builtin_memcpy(&v, s + n, 16);
__builtin_memcpy(&w, s + n + 16, 16);
__builtin_memcpy(d + n, &v, 16);
__builtin_memcpy(d + n + 16, &w, 16);
} while (n >= 32);
} else {
i = 0;
do {
__builtin_memcpy(&v, s + i, 16);
__builtin_memcpy(&w, s + i + 16, 16);
__builtin_memcpy(d + i, &v, 16);
__builtin_memcpy(d + i + 16, &w, 16);
} while ((i += 32) + 32 <= n);
d += i;
s += i;
n -= i;
}
switch (n) {
case 0:
return r;
case 17 ... 31:
__builtin_memcpy(&v, s, 16);
__builtin_memcpy(&w, s + n - 16, 16);
__builtin_memcpy(d, &v, 16);
__builtin_memcpy(d + n - 16, &w, 16);
return r;
case 9 ... 15:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(&b, s + n - 8, 8);
__builtin_memcpy(d, &a, 8);
__builtin_memcpy(d + n - 8, &b, 8);
return r;
case 5 ... 7:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(&b, s + n - 4, 4);
__builtin_memcpy(d, &a, 4);
__builtin_memcpy(d + n - 4, &b, 4);
return r;
case 16:
__builtin_memcpy(&v, s, 16);
__builtin_memcpy(d, &v, 16);
return r;
case 8:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(d, &a, 8);
return r;
case 4:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(d, &a, 4);
return r;
case 1:
*d = *s;
return r;
case 2:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(d, &a, 2);
return r;
case 3:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(&b, s + 1, 2);
__builtin_memcpy(d, &a, 2);
__builtin_memcpy(d + 1, &b, 2);
return r;
default:
unreachable;
}
static noasan void *MoveMemoryIntervals(struct MemoryInterval *d,
const struct MemoryInterval *s, int n) {
int i;
assert(n >= 0);
if (d > s) {
for (i = n; i--;) {
d[i] = s[i];
}
} else {
for (i = 0; i < n; ++i) {
d[i] = s[i];
}
}
return d;
}
#ifndef __FSANITIZE_ADDRESS__
#define MoveMemoryNoAsan memmove
#endif
static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
int n) {
assert(i >= 0);
assert(i + n <= mm->i);
MoveMemoryNoAsan(mm->p + i, mm->p + i + n,
(intptr_t)(mm->p + mm->i) - (intptr_t)(mm->p + i + n));
MoveMemoryIntervals(mm->p + i, mm->p + i + n, mm->i - (i + n));
mm->i -= n;
}
static noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
static noasan void MapNewMappingArray(struct MemoryIntervals *mm) {
void *a;
int i, x, y, g;
size_t n, m, f;
int prot, flags;
struct DirectMap dm;
struct MemoryInterval *p, *q;
assert(mm->i);
assert(AreMemoryIntervalsOk(mm));
n = mm->n;
n = n * sizeof(*mm->p);
n = ROUNDUP(n, FRAMESIZE);
if (mm->p == mm->s) {
m = n;
q = 0;
} else {
q = mm->p;
m = n + (n >> 1);
m = ROUNDUP(m, FRAMESIZE);
}
/*
* find a hole in the automap range
* we pad the sides for easier insertion logic
* only time this fails is MODE=tiny which makes no stack
*/
i = 0;
f = m >> 16;
for (;;) {
if (++i == mm->i || mm->p[i].x - mm->p[i - 1].y >= 1 + f + 1) {
x = mm->p[i - 1].y + 1;
y = x + f - 1;
a = (void *)((intptr_t)((uint64_t)x << 32) >> 16);
if (i == mm->i || (kAutomapStart <= (intptr_t)a &&
(intptr_t)a + m < kAutomapStart + kAutomapSize)) {
break;
}
}
}
flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
prot = PROT_READ | PROT_WRITE;
SYSDEBUG("MapNewMappingArray(0x%x, 0x%x) %d/%d/%d", a, m, i, mm->i, mm->n);
dm = sys_mmap(a, m, prot, flags, -1, 0);
if ((p = dm.addr) != MAP_FAILED) {
MoveMemoryIntervals(p, mm->p, i);
MoveMemoryIntervals(p + i + 1, mm->p + i, mm->i - i);
mm->i += 1;
mm->n = m / sizeof(*mm->p);
mm->p = p;
mm->p[i].x = x;
mm->p[i].y = y;
mm->p[i].h = dm.maphandle;
mm->p[i].prot = prot;
mm->p[i].flags = flags;
if (q) {
munmap(q, n);
}
if (IsAsan()) {
__asan_map_shadow((uintptr_t)a, m);
}
SYSDEBUG("MapNewMappingArray() succeeded");
} else {
SYSDEBUG("MapNewMappingArray() failed: %s", strerror(errno));
}
assert(AreMemoryIntervalsOk(mm));
}
noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
int rc;
void *p;
size_t n;
static bool noreentry;
rc = 0;
assert(i >= 0);
assert(i <= mm->i);
assert(mm->i < mm->n);
MoveMemoryNoAsan(mm->p + i + 1, mm->p + i,
(intptr_t)(mm->p + mm->i) - (intptr_t)(mm->p + i));
if (++mm->i > (mm->n >> 1) && cmpxchg(&noreentry, false, true)) {
n = mm->n << 1;
p = weaken(malloc) ? weaken(malloc)(n * sizeof(*mm->p)) : 0;
if (p) {
memcpy(p, mm->p, mm->i * sizeof(*mm->p));
if (mm->p != mm->s && weaken(free)) {
weaken(free)(mm->p);
}
mm->p = p;
mm->n = n;
} else {
rc = enomem();
}
noreentry = false;
assert(mm->n >= 0);
if (mm->i == mm->n) {
SYSDEBUG("CreateMemoryInterval() failed");
return enomem();
}
MoveMemoryIntervals(mm->p + i + 1, mm->p + i, mm->i++ - i);
return 0;
}
@ -272,6 +212,9 @@ noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
mm->p[i].h = h;
mm->p[i].prot = prot;
mm->p[i].flags = flags;
if (mm->i >= mm->n / 2) {
MapNewMappingArray(mm);
}
}
return 0;
}

View file

@ -37,8 +37,6 @@ struct MemoryIntervals {
extern hidden struct MemoryIntervals _mmi;
unsigned FindMemoryInterval(const struct MemoryIntervals *,
int) nosideeffect hidden;
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden;
void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden;
int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int,
@ -48,6 +46,22 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int,
void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden;
int UntrackMemoryIntervals(void *, size_t) hidden;
static inline noasan unsigned FindMemoryInterval(
const struct MemoryIntervals *mm, int x) {
unsigned l, m, r;
l = 0;
r = mm->i;
while (l < r) {
m = (l + r) >> 1;
if (mm->p[m].y < x) {
l = m + 1;
} else {
r = m;
}
}
return l;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_ */

View file

@ -17,12 +17,13 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
static noasan void *GetFrameAddr(int f) {
static inline noasan void *GetFrameAddr(int f) {
intptr_t a;
a = f;
a *= FRAMESIZE;
@ -31,8 +32,14 @@ static noasan void *GetFrameAddr(int f) {
noasan void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) {
int i, ok;
size_t size;
char *addr, *last;
for (i = l; i <= r; ++i) {
ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x));
addr = GetFrameAddr(mm->p[i].x);
last = GetFrameAddr(mm->p[i].y);
SYSDEBUG("UnmapViewOfFile(addr:0x%x, size:0x%x, hand:0x%x)", addr,
last - addr + FRAMESIZE, mm->p[i].h);
ok = UnmapViewOfFile(addr);
assert(ok);
ok = CloseHandle(mm->p[i].h);
assert(ok);

View file

@ -23,6 +23,7 @@
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/backtrace.internal.h"
#include "libc/macros.internal.h"
#include "libc/rand/rand.h"
#include "libc/runtime/directmap.internal.h"
@ -61,6 +62,8 @@
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
struct DirectMap dm;
int i, x, n, m, a, b, f;
SYSDEBUG("mmap(0x%x, 0x%x, %d, 0x%x, %d, %d)", addr, size, prot, flags, fd,
off);
if (!size) return VIP(einval());
if (size > 0x0000010000000000ull) return VIP(enomem());
if (!ALIGNED(off)) return VIP(einval());
@ -98,6 +101,7 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
}
dm = sys_mmap(addr, size, prot, f, fd, off);
if (dm.addr == MAP_FAILED || dm.addr != addr) {
SYSDEBUG("sys_mmap failed");
return MAP_FAILED;
}
a = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16;

View file

@ -22,7 +22,7 @@
#include "libc/nt/memory.h"
#include "libc/runtime/memtrack.internal.h"
textwindows int sys_msync_nt(void *addr, size_t size, int flags) {
noasan textwindows int sys_msync_nt(void *addr, size_t size, int flags) {
int x, y, l, r, i;
x = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16;
y = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16;

View file

@ -17,7 +17,9 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
@ -42,11 +44,14 @@
* and for files size needs to be perfect to the byte bc openbsd
* @return 0 on success, or -1 w/ errno
*/
int munmap(void *addr, size_t size) {
noasan int munmap(void *addr, size_t size) {
int rc;
/* TODO(jart): are we unmapping shadows? */
SYSDEBUG("munmap(0x%x, 0x%x)", addr, size);
if (!ALIGNED(addr) || !CANONICAL(addr) || !size) return einval();
if (UntrackMemoryIntervals(addr, size) == -1) return -1;
if (IsWindows()) return 0;
if (IsMetal()) sys_munmap_metal(addr, size);
SYSDEBUG("sys_munmap(0x%x, 0x%x)", addr, size);
return sys_munmap(addr, size);
}

View file

@ -17,15 +17,24 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/alg.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/runtime/carsort.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
/**
* Maps debuggable binary into memory and indexes symbol addresses.
@ -33,30 +42,88 @@
* @return object freeable with CloseSymbolTable(), or NULL w/ errno
*/
struct SymbolTable *OpenSymbolTable(const char *filename) {
unsigned i, j;
int fd;
void *map;
struct stat st;
size_t n, m, tsz;
unsigned i, j, k, x;
const Elf64_Ehdr *elf;
const char *name_base;
struct SymbolTable *t;
const Elf64_Sym *symtab, *sym;
t = MAP_FAILED;
if (filename && (t = mapanon(BIGPAGESIZE)) != MAP_FAILED &&
MapElfRead(filename, &t->mf) &&
(t->name_base = GetElfStringTable(t->elf, t->elfsize)) != NULL &&
(symtab = GetElfSymbolTable(t->elf, t->elfsize, &t->count)) &&
sizeof(struct SymbolTable) + sizeof(struct Symbol) * t->count <
(t->scratch = BIGPAGESIZE)) {
GetElfVirtualAddressRange(t->elf, t->elfsize, &t->addr_base, &t->addr_end);
for (j = i = 0; i < t->count; ++i) {
sym = &symtab[i];
if (IsElfSymbolContent(sym) &&
(sym->st_value >= t->addr_base && sym->st_value <= t->addr_end)) {
t->symbols[j].addr_rva = (unsigned)(sym->st_value - t->addr_base);
t->symbols[j].name_rva = sym->st_name;
j++;
}
}
t->count = j;
carsort1000(t->count, (void *)t->symbols);
} else {
CloseSymbolTable(&t);
ptrdiff_t names_offset, name_base_offset, extra_offset;
map = MAP_FAILED;
if ((fd = open(filename, O_RDONLY)) == -1) return 0;
if (fstat(fd, &st) == -1) goto SystemError;
if (st.st_size > INT_MAX) goto RaiseE2big;
if (st.st_size < 64) goto RaiseEnoexec;
elf = map = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) goto SystemError;
if (READ32LE(map) != READ32LE("\177ELF")) goto RaiseEnoexec;
if (!(name_base = GetElfStrs(map, st.st_size, &m))) goto RaiseEnobufs;
if (!(symtab = GetElfSymbolTable(map, st.st_size, &n))) goto RaiseEnobufs;
tsz = 0;
tsz += sizeof(struct SymbolTable);
tsz += sizeof(struct Symbol) * n;
names_offset = tsz;
tsz += sizeof(unsigned) * n;
name_base_offset = tsz;
tsz += m;
extra_offset = tsz;
tsz = ROUNDUP(tsz, FRAMESIZE);
t = mmap(0, tsz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (t == MAP_FAILED) goto SystemError;
if (IsAsan()) {
__asan_poison((intptr_t)((char *)t + extra_offset), tsz - extra_offset,
kAsanHeapOverrun);
}
return t == MAP_FAILED ? NULL : t;
t->mapsize = tsz;
t->names = (const unsigned *)((const char *)t + names_offset);
t->name_base = (const char *)((const char *)t + name_base_offset);
GetElfVirtualAddressRange(elf, st.st_size, &t->addr_base, &t->addr_end);
memcpy(t->name_base, name_base, m);
--t->addr_end;
for (j = i = 0; i < n; ++i) {
sym = symtab + i;
if (!(sym->st_size > 0 && (ELF64_ST_TYPE(sym->st_info) == STT_FUNC ||
ELF64_ST_TYPE(sym->st_info) == STT_OBJECT))) {
continue;
}
if (sym->st_value > t->addr_end) continue;
if (sym->st_value < t->addr_base) continue;
x = sym->st_value - t->addr_base;
for (k = j; k && x <= t->symbols[k - 1].x; --k) {
t->symbols[k] = t->symbols[k - 1];
t->names[k] = t->names[k - 1];
}
if (k && t->symbols[k - 1].y >= x) {
t->symbols[k - 1].y = x - 1;
}
t->names[k] = sym->st_name;
t->symbols[k].x = x;
if (sym->st_size) {
t->symbols[k].y = x + sym->st_size - 1;
} else {
t->symbols[k].y = t->addr_end - t->addr_base;
}
j++;
}
t->count = j;
munmap(map, st.st_size);
close(fd);
return t;
RaiseE2big:
errno = E2BIG;
goto SystemError;
RaiseEnobufs:
errno = ENOBUFS;
goto SystemError;
RaiseEnoexec:
errno = ENOEXEC;
SystemError:
if (map != MAP_FAILED) {
munmap(map, st.st_size);
}
close(fd);
return 0;
}

View file

@ -81,6 +81,7 @@ int acct(const char *);
bool _isheap(void *);
int NtGetVersion(void);
long missingno();
void __oom_hook(size_t);
void __print(const void *, size_t);
void __print_string(const char *);
void _loadxmm(void *);

View file

@ -57,6 +57,7 @@ $(LIBC_RUNTIME_A).pkg: \
$(LIBC_RUNTIME_A_OBJS) \
$(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/runtime/printf.o \
o/$(MODE)/libc/runtime/abort-nt.o \
o/$(MODE)/libc/runtime/arememoryintervalsok.o \
o/$(MODE)/libc/runtime/assertfail.o \
@ -64,6 +65,8 @@ o/$(MODE)/libc/runtime/directmap.o \
o/$(MODE)/libc/runtime/directmapnt.o \
o/$(MODE)/libc/runtime/findmemoryinterval.o \
o/$(MODE)/libc/runtime/ftrace.greg.o \
o/$(MODE)/libc/runtime/ftracer.o \
o/$(MODE)/libc/runtime/ezmap.o \
o/$(MODE)/libc/runtime/getdosargv.o \
o/$(MODE)/libc/runtime/getdosenviron.o \
o/$(MODE)/libc/runtime/hook.greg.o \
@ -78,9 +81,12 @@ o/$(MODE)/libc/runtime/winmain.greg.o: \
OVERRIDE_CFLAGS += \
$(NO_MAGIC)
o/$(MODE)/libc/runtime/printf.o \
o/$(MODE)/libc/runtime/memtrack.o \
o/$(MODE)/libc/runtime/mman.greg.o: \
OVERRIDE_CFLAGS += \
-ffreestanding
-ffreestanding \
-mgeneral-regs-only
o/$(MODE)/libc/runtime/ftrace.greg.o: \
OVERRIDE_CFLAGS += \

View file

@ -1,30 +1,24 @@
#ifndef COSMOPOLITAN_LIBC_SYMBOLS_H_
#define COSMOPOLITAN_LIBC_SYMBOLS_H_
#include "libc/assert.h"
#include "libc/elf/elf.h"
#include "libc/runtime/ezmap.internal.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Symbol {
unsigned addr_rva;
unsigned name_rva;
unsigned x; /* start (relative to addr_base) */
unsigned y; /* start + size - 1 (inclusive) */
};
struct SymbolTable {
union {
struct MappedFile mf;
struct {
int64_t fd;
struct Elf64_Ehdr *elf;
size_t elfsize;
};
};
size_t scratch;
size_t count;
intptr_t addr_base;
intptr_t addr_end;
const char *name_base;
struct Symbol symbols[];
size_t count; /* of `symbols` */
size_t mapsize; /* of this object */
intptr_t addr_base; /* IMAGE_BASE_VIRTUAL */
intptr_t addr_end; /* _end - 1 */
unsigned *names; /* relative to `name_base` */
char *name_base; /* double-nul terminated w/ empty first */
struct Symbol symbols[]; /* sorted and non-overlapping intervals */
};
struct SymbolTable *GetSymbolTable(void);
@ -34,6 +28,35 @@ struct SymbolTable *OpenSymbolTable(const char *) nodiscard;
int CloseSymbolTable(struct SymbolTable **);
void __hook(void *, struct SymbolTable *);
forceinline int GetSymbol(struct SymbolTable *t, intptr_t a) {
unsigned l, m, r, n, k;
if (t) {
l = 0;
r = n = t->count;
k = a - t->addr_base;
while (l < r) {
m = (l + r) >> 1;
if (t->symbols[m].y < k) {
l = m + 1;
} else {
r = m;
}
}
if (l < n && t->symbols[l].x <= k && k <= t->symbols[l].y) {
return l;
}
}
return -1;
}
forceinline char *GetSymbolName(struct SymbolTable *t, int s) {
if (t && s != -1) {
return t->name_base + t->names[s];
} else {
return 0;
}
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_SYMBOLS_H_ */

View file

@ -22,7 +22,9 @@
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/filemapflags.h"
@ -41,7 +43,10 @@
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/internal.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#define AT_EXECFN 31L
#define MAP_ANONYMOUS 32
#define MAP_PRIVATE 2
#define PROT_EXEC 4
@ -59,11 +64,15 @@ struct WinArgs {
intptr_t auxv[2][2];
char argblock[ARG_MAX];
char envblock[ARG_MAX];
union {
char execfn[PATH_MAX * 2];
char16_t execfn16[PATH_MAX];
};
};
uint32_t __ntconsolemode;
static noasan textwindows void MakeLongDoubleLongAgain(void) {
static noasan textwindows noinstrument void MakeLongDoubleLongAgain(void) {
/* 8087 FPU Control Word
IM: Invalid Operation
DM: Denormal Operand
@ -81,7 +90,28 @@ static noasan textwindows void MakeLongDoubleLongAgain(void) {
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw));
}
static noasan textwindows wontreturn void WinMainNew(void) {
static noasan textwindows noinstrument bool GetExePath(struct WinArgs *wa) {
uint64_t w;
wint_t x, y;
uint32_t i, j;
if (!GetModuleFileName(0, wa->execfn16, ARRAYLEN(wa->execfn16))) return 0;
for (i = j = 0; (x = wa->execfn16[i++] & 0xffff);) {
if (!IsUcs2(x)) {
y = wa->execfn16[i++] & 0xffff;
x = MergeUtf16(x, y);
}
if (x == '\\') x = '/';
w = tpenc(x);
do {
if (j + 1 >= i * sizeof(char16_t)) return false;
wa->execfn[j++] = w;
} while ((w >>= 8));
}
wa->execfn[j] = 0;
return true;
}
static noasan textwindows wontreturn noinstrument void WinMainNew(void) {
int64_t h;
int version;
size_t size;
@ -110,7 +140,7 @@ static noasan textwindows wontreturn void WinMainNew(void) {
}
_mmi.p = _mmi.s;
_mmi.n = OPEN_MAX;
addr = version < 10 ? 0xff00000 : 0x777000000000;
addr = version < 10 ? 0x10000000 - STACKSIZE : 0x777000000000;
size = ROUNDUP(STACKSIZE + sizeof(struct WinArgs), FRAMESIZE);
MapViewOfFileExNuma((_mmi.p[0].h = CreateFileMappingNuma(
-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
@ -131,13 +161,13 @@ static noasan textwindows wontreturn void WinMainNew(void) {
}
}
env16 = GetEnvironmentStrings();
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock), wa->envp,
ARRAYLEN(wa->envp));
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
ARRAYLEN(wa->envp) - 1);
FreeEnvironmentStrings(env16);
wa->auxv[1][0] = pushpop(0L);
wa->auxv[1][1] = pushpop(0L);
wa->auxv[0][0] = pushpop(31L);
wa->auxv[0][1] = (intptr_t)wa->argv[0];
if (GetExePath(wa)) {
wa->auxv[0][0] = pushpop(AT_EXECFN);
wa->auxv[0][1] = (intptr_t)wa->execfn;
}
_jmpstack((char *)addr + STACKSIZE, cosmo, count, wa->argv, wa->envp,
wa->auxv);
}
@ -174,8 +204,10 @@ static noasan textwindows wontreturn void WinMainNew(void) {
*
* @param hInstance call GetModuleHandle(NULL) from main if you need it
*/
noasan textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
const char *lpCmdLine, int nCmdShow) {
noasan textwindows noinstrument int64_t WinMain(int64_t hInstance,
int64_t hPrevInstance,
const char *lpCmdLine,
int nCmdShow) {
MakeLongDoubleLongAgain();
if (weaken(WinSockInit)) weaken(WinSockInit)();
if (weaken(WinMainForked)) weaken(WinMainForked)();