mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Add malloc logging tool
STATIC_YOINK("enable_memory_log");
This commit is contained in:
parent
7e9fb0a9f1
commit
cb67223051
25 changed files with 502 additions and 78 deletions
|
@ -13,12 +13,37 @@
|
|||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
#define CHUNK 32768
|
||||
|
||||
#define USAGE \
|
||||
" <STDIN >STDOUT\n\
|
||||
\n\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
Zlib Compressor\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-?\n\
|
||||
-h help\n\
|
||||
-0 disable compression\n\
|
||||
-1 fastest compression\n\
|
||||
-4 coolest compression\n\
|
||||
-9 maximum compression\n\
|
||||
-F fixed strategy (advanced)\n\
|
||||
-L filtered strategy (advanced)\n\
|
||||
-R run length strategy (advanced)\n\
|
||||
-H huffman only strategy (advanced)\n\
|
||||
\n"
|
||||
|
||||
// clang-format off
|
||||
// make -j8 o//examples && dd if=/dev/urandom count=100 | tee a | o//examples/compress.com | o//examples/decompress.com >b && sha1sum a b
|
||||
/*
|
||||
|
@ -35,18 +60,67 @@
|
|||
# level 9 75016 compress 5.4 MB/s decompress 344 MB/s
|
||||
m=
|
||||
make -j8 MODE=$m o/$m/examples || exit
|
||||
for level in $(seq 0 9); do
|
||||
o/$m/examples/compress.com $level <o/dbg/third_party/python/python.com | dd count=10000 2>/tmp/info >/tmp/comp
|
||||
for level in $(seq 1 9); do
|
||||
for strategy in F L R H; do
|
||||
o/$m/examples/compress.com -$strategy$level <o/dbg/third_party/python/python.com | dd count=10000 2>/tmp/info >/tmp/comp
|
||||
compspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info)
|
||||
o/$m/examples/decompress.com $level </tmp/comp | dd count=10000 2>/tmp/info >/dev/null
|
||||
o/$m/examples/decompress.com </tmp/comp | dd count=10000 2>/tmp/info >/dev/null
|
||||
decompspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info)
|
||||
size=$(o/$m/examples/compress.com $level <o/$m/examples/compress.com | wc -c)
|
||||
echo "level $level $size compress $compspeed decompress $decompspeed"
|
||||
size=$(o/$m/examples/compress.com -$strategy$level <o/$m/examples/compress.com | wc -c)
|
||||
echo "level $strategy $level $size compress $compspeed decompress $decompspeed"
|
||||
done
|
||||
done
|
||||
*/
|
||||
// clang-format on
|
||||
|
||||
int compressor(int infd, int outfd, int level) {
|
||||
int level;
|
||||
int strategy;
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE *f) {
|
||||
fputs("usage: ", f);
|
||||
fputs(program_invocation_name, f);
|
||||
fputs(USAGE, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?hFLRH0123456789")) != -1) {
|
||||
switch (opt) {
|
||||
case 'F':
|
||||
strategy = Z_FIXED;
|
||||
break;
|
||||
case 'L':
|
||||
strategy = Z_FILTERED;
|
||||
break;
|
||||
case 'R':
|
||||
strategy = Z_RLE;
|
||||
break;
|
||||
case 'H':
|
||||
strategy = Z_HUFFMAN_ONLY;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
level = opt - '0';
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int compressor(int infd, int outfd) {
|
||||
z_stream zs;
|
||||
int rc, flush;
|
||||
unsigned have;
|
||||
|
@ -57,8 +131,7 @@ int compressor(int infd, int outfd, int level) {
|
|||
zs.zalloc = 0;
|
||||
zs.zfree = 0;
|
||||
zs.opaque = 0;
|
||||
rc = deflateInit2(&zs, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
rc = deflateInit2(&zs, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, strategy);
|
||||
if (rc != Z_OK) return rc;
|
||||
do {
|
||||
rc = read(infd, inbuf, CHUNK);
|
||||
|
@ -105,13 +178,11 @@ const char *zerr(int rc) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int rc, level;
|
||||
if (argc > 1) {
|
||||
level = atoi(argv[1]);
|
||||
} else {
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
}
|
||||
rc = compressor(0, 1, level);
|
||||
int rc;
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
strategy = Z_DEFAULT_STRATEGY;
|
||||
GetOpts(argc, argv);
|
||||
rc = compressor(0, 1);
|
||||
if (rc == Z_OK) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -33,12 +33,14 @@
|
|||
m=
|
||||
make -j8 MODE=$m o/$m/examples || exit
|
||||
for level in $(seq 0 9); do
|
||||
o/$m/examples/compress.com $level <o/dbg/third_party/python/python.com | dd count=10000 2>/tmp/info >/tmp/comp
|
||||
for strategy in F L R H; do
|
||||
o/$m/examples/compress.com -$strategy$level <o/dbg/third_party/python/python.com | dd count=10000 2>/tmp/info >/tmp/comp
|
||||
compspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info)
|
||||
o/$m/examples/decompress.com $level </tmp/comp | dd count=10000 2>/tmp/info >/dev/null
|
||||
o/$m/examples/decompress.com </tmp/comp | dd count=10000 2>/tmp/info >/dev/null
|
||||
decompspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info)
|
||||
size=$(o/$m/examples/compress.com $level <o/$m/examples/compress.com | wc -c)
|
||||
echo "level $level $size compress $compspeed decompress $decompspeed"
|
||||
size=$(o/$m/examples/compress.com -$strategy$level <o/$m/examples/compress.com | wc -c)
|
||||
echo "level $strategy $level $size compress $compspeed decompress $decompspeed"
|
||||
done
|
||||
done
|
||||
*/
|
||||
// clang-format on
|
||||
|
|
|
@ -20,6 +20,7 @@ i32 __sys_execve(const char *, char *const[], char *const[]) hidden;
|
|||
i32 __sys_fcntl(i32, i32, ...) hidden;
|
||||
i32 __sys_fstat(i32, void *) hidden;
|
||||
i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
|
||||
i32 __sys_gettid(i64 *) hidden;
|
||||
i32 __sys_munmap(void *, u64) hidden;
|
||||
i32 __sys_openat(i32, const char *, i32, u32) hidden;
|
||||
i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
|
||||
|
@ -51,6 +52,7 @@ i32 sys_getpriority(i32, u32) hidden;
|
|||
i32 sys_getresgid(u32 *, u32 *, u32 *);
|
||||
i32 sys_getresuid(u32 *, u32 *, u32 *);
|
||||
i32 sys_getsid(int) hidden;
|
||||
i32 sys_gettid(void) hidden;
|
||||
i32 sys_ioctl(i32, u64, ...) hidden;
|
||||
i32 sys_kill(i32, i32, i32) hidden;
|
||||
i32 sys_linkat(i32, const char *, i32, const char *, i32) hidden;
|
||||
|
@ -108,7 +110,6 @@ i64 sys_write(i32, const void *, u64) hidden;
|
|||
u32 sys_getegid(void) hidden;
|
||||
u32 sys_geteuid(void) hidden;
|
||||
u32 sys_getgid(void) hidden;
|
||||
u32 sys_gettid(void) hidden;
|
||||
u32 sys_getuid(void) hidden;
|
||||
u32 sys_umask(u32) hidden;
|
||||
void *__sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/setjmp.internal.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
@ -32,8 +33,13 @@
|
|||
* @noreturn
|
||||
*/
|
||||
privileged wontreturn void _Exit1(int rc) {
|
||||
jmp_buf *jb;
|
||||
struct WinThread *wt;
|
||||
STRACE("_Exit1(%d)", rc);
|
||||
if (__tls_enabled) {
|
||||
jb = (jmp_buf *)(__get_tls() + 0x08);
|
||||
longjmp(*jb, rc);
|
||||
}
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
asm volatile("xor\t%%r10d,%%r10d\n\t"
|
||||
"syscall"
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/gc.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
|
@ -150,11 +149,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
strlen(" (discriminator ") - 1)) &&
|
||||
(p3 = memchr(p2, '\n', got - (p2 - p1)))) {
|
||||
if (p3 > p2 && p3[-1] == '\r') --p3;
|
||||
__write(p1, p2 - p1);
|
||||
write(2, p1, p2 - p1);
|
||||
got -= p3 - p1;
|
||||
p1 += p3 - p1;
|
||||
} else {
|
||||
__write(p1, got);
|
||||
write(2, p1, got);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
297
libc/log/memlog.c
Normal file
297
libc/log/memlog.c
Normal file
|
@ -0,0 +1,297 @@
|
|||
/*-*- 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 2022 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/atomic.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/hook/hook.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "third_party/dlmalloc/dlmalloc.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Malloc Logging
|
||||
*
|
||||
* If you put the following in your main file:
|
||||
*
|
||||
* STATIC_YOINK("enable_memory_log");
|
||||
*
|
||||
* Then memory allocations with constant backtraces will be logged to
|
||||
* standard error. The columns printed are
|
||||
*
|
||||
* MEM TID OP USAGE PTR OLD SIZE CALLER1 CALLER2 CALLER3 CALLER4
|
||||
*
|
||||
* delimited by spaces. For example, to see peak malloc usage:
|
||||
*
|
||||
* ./myprog.com 2>log
|
||||
* grep ^MEM log | sort -nk4 | tail -n10
|
||||
*
|
||||
* To see the largest allocations:
|
||||
*
|
||||
* ./myprog.com 2>log
|
||||
* grep ^MEM log | grep -v free | sort -nk7 | tail -n10
|
||||
*/
|
||||
|
||||
static struct Memlog {
|
||||
void (*free)(void *);
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*memalign)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void *(*realloc_in_place)(void *, size_t);
|
||||
size_t (*bulk_free)(void *[], size_t);
|
||||
struct Allocs {
|
||||
long i, n, f;
|
||||
struct Alloc {
|
||||
void *addr;
|
||||
long size;
|
||||
} * p;
|
||||
} allocs;
|
||||
long usage;
|
||||
} __memlog;
|
||||
|
||||
_Alignas(64) static int __memlog_lock_obj;
|
||||
|
||||
static void __memlog_lock(void) {
|
||||
_spinlock(&__memlog_lock_obj);
|
||||
}
|
||||
|
||||
static void __memlog_unlock(void) {
|
||||
_spunlock(&__memlog_lock_obj);
|
||||
}
|
||||
|
||||
static long __memlog_size(void *p) {
|
||||
return malloc_usable_size(p) + 16;
|
||||
}
|
||||
|
||||
static void __memlog_backtrace(struct StackFrame *frame, intptr_t *a,
|
||||
intptr_t *b, intptr_t *c, intptr_t *d) {
|
||||
*a = *b = *c = *d = 0;
|
||||
if (!frame) return;
|
||||
*a = frame->addr;
|
||||
if (!(frame = frame->next)) return;
|
||||
*b = frame->addr;
|
||||
if (!(frame = frame->next)) return;
|
||||
*c = frame->addr;
|
||||
if (!(frame = frame->next)) return;
|
||||
*d = frame->addr;
|
||||
}
|
||||
|
||||
static long __memlog_find(void *p) {
|
||||
long i;
|
||||
for (i = 0; i < __memlog.allocs.i; ++i) {
|
||||
if (__memlog.allocs.p[i].addr == p) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void __memlog_insert(void *p) {
|
||||
long i, n, n2;
|
||||
struct Alloc *p2;
|
||||
n = __memlog_size(p);
|
||||
for (i = __memlog.allocs.f; i < __memlog.allocs.i; ++i) {
|
||||
if (!__memlog.allocs.p[i].addr) {
|
||||
__memlog.allocs.p[i].addr = p;
|
||||
__memlog.allocs.p[i].size = n;
|
||||
__memlog.usage += n;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (i == __memlog.allocs.n) {
|
||||
p2 = __memlog.allocs.p;
|
||||
n2 = __memlog.allocs.n;
|
||||
n2 += 1;
|
||||
n2 += n2 >> 1;
|
||||
if ((p2 = dlrealloc(p2, n2 * sizeof(*p2)))) {
|
||||
__memlog.allocs.p = p2;
|
||||
__memlog.allocs.n = n2;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
__memlog.allocs.p[i].addr = p;
|
||||
__memlog.allocs.p[i].size = n;
|
||||
__memlog.allocs.i++;
|
||||
__memlog.usage += n;
|
||||
}
|
||||
|
||||
static void __memlog_update(void *p2, void *p) {
|
||||
long i, n;
|
||||
n = __memlog_size(p2);
|
||||
for (i = 0; i < __memlog.allocs.i; ++i) {
|
||||
if (__memlog.allocs.p[i].addr == p) {
|
||||
__memlog.usage += n - __memlog.allocs.p[i].size;
|
||||
__memlog.allocs.p[i].addr = p2;
|
||||
__memlog.allocs.p[i].size = n;
|
||||
assert(__memlog.usage >= 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(!"this corruption");
|
||||
}
|
||||
|
||||
static void __memlog_log(struct StackFrame *frame, const char *op, void *res,
|
||||
void *old, size_t n) {
|
||||
intptr_t a, b, c, d;
|
||||
__memlog_backtrace(frame, &a, &b, &c, &d);
|
||||
kprintf("MEM %6P %7s %12ld %14p %14p %8zu %t %t %t %t\n", op,
|
||||
atomic_load(&__memlog.usage), res, old, n, a, b, c, d);
|
||||
}
|
||||
|
||||
static void __memlog_free(void *p) {
|
||||
long i, n;
|
||||
if (!p) return;
|
||||
__memlog_lock();
|
||||
if ((i = __memlog_find(p)) != -1) {
|
||||
n = __memlog.allocs.p[i].size;
|
||||
__memlog.allocs.p[i].addr = 0;
|
||||
__memlog.usage -= __memlog.allocs.p[i].size;
|
||||
__memlog.allocs.f = MIN(__memlog.allocs.f, i);
|
||||
assert(__memlog.usage >= 0);
|
||||
} else {
|
||||
kprintf("memlog could not find %p\n", p);
|
||||
assert(!"this corruption");
|
||||
n = -1;
|
||||
}
|
||||
__memlog_unlock();
|
||||
assert(__memlog.free);
|
||||
__memlog.free(p);
|
||||
__memlog_log(__builtin_frame_address(0), "free", 0, p, n);
|
||||
}
|
||||
|
||||
static void *__memlog_malloc(size_t n) {
|
||||
void *res;
|
||||
assert(__memlog.malloc);
|
||||
if ((res = __memlog.malloc(n))) {
|
||||
__memlog_lock();
|
||||
__memlog_insert(res);
|
||||
__memlog_unlock();
|
||||
__memlog_log(__builtin_frame_address(0), "malloc", res, 0, n);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *__memlog_calloc(size_t n, size_t z) {
|
||||
void *res;
|
||||
assert(__memlog.calloc);
|
||||
if ((res = __memlog.calloc(n, z))) {
|
||||
__memlog_lock();
|
||||
__memlog_insert(res);
|
||||
__memlog_unlock();
|
||||
__memlog_log(__builtin_frame_address(0), "malloc", res, 0, n * z);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *__memlog_memalign(size_t l, size_t n) {
|
||||
void *res;
|
||||
assert(__memlog.memalign);
|
||||
if ((res = __memlog.memalign(l, n))) {
|
||||
__memlog_lock();
|
||||
__memlog_insert(res);
|
||||
__memlog_unlock();
|
||||
__memlog_log(__builtin_frame_address(0), "malloc", res, 0, n);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *__memlog_realloc_impl(void *p, size_t n,
|
||||
void *(*f)(void *, size_t),
|
||||
struct StackFrame *frame) {
|
||||
void *res;
|
||||
assert(f);
|
||||
if ((res = f(p, n))) {
|
||||
__memlog_lock();
|
||||
if (p) {
|
||||
__memlog_update(res, p);
|
||||
} else {
|
||||
__memlog_insert(res);
|
||||
}
|
||||
__memlog_unlock();
|
||||
__memlog_log(frame, "realloc", res, p, n);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *__memlog_realloc(void *p, size_t n) {
|
||||
return __memlog_realloc_impl(p, n, __memlog.realloc,
|
||||
__builtin_frame_address(0));
|
||||
}
|
||||
|
||||
static void *__memlog_realloc_in_place(void *p, size_t n) {
|
||||
return __memlog_realloc_impl(p, n, __memlog.realloc_in_place,
|
||||
__builtin_frame_address(0));
|
||||
}
|
||||
|
||||
static size_t __memlog_bulk_free(void *p[], size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
__memlog_free(p[i]);
|
||||
p[i] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static textexit void __memlog_destroy(void) {
|
||||
__memlog_lock();
|
||||
hook_free = __memlog.free;
|
||||
hook_malloc = __memlog.malloc;
|
||||
hook_calloc = __memlog.calloc;
|
||||
hook_realloc = __memlog.realloc;
|
||||
hook_memalign = __memlog.memalign;
|
||||
hook_bulk_free = __memlog.bulk_free;
|
||||
hook_realloc_in_place = __memlog.realloc_in_place;
|
||||
dlfree(__memlog.allocs.p);
|
||||
__memlog.allocs.p = 0;
|
||||
__memlog.allocs.i = 0;
|
||||
__memlog.allocs.n = 0;
|
||||
__memlog_unlock();
|
||||
}
|
||||
|
||||
static textstartup void __memlog_init(void) {
|
||||
GetSymbolTable();
|
||||
__memlog_lock();
|
||||
__memlog.free = hook_free;
|
||||
hook_free = __memlog_free;
|
||||
__memlog.malloc = hook_malloc;
|
||||
hook_malloc = __memlog_malloc;
|
||||
__memlog.calloc = hook_calloc;
|
||||
hook_calloc = __memlog_calloc;
|
||||
__memlog.realloc = hook_realloc;
|
||||
hook_realloc = __memlog_realloc;
|
||||
__memlog.memalign = hook_memalign;
|
||||
hook_memalign = __memlog_memalign;
|
||||
__memlog.bulk_free = hook_bulk_free;
|
||||
hook_bulk_free = __memlog_bulk_free;
|
||||
__memlog.realloc_in_place = hook_realloc_in_place;
|
||||
hook_realloc_in_place = __memlog_realloc_in_place;
|
||||
atexit(__memlog_destroy);
|
||||
__memlog_unlock();
|
||||
}
|
||||
|
||||
const void *const enable_memory_log[] initarray = {
|
||||
__memlog_init,
|
||||
};
|
|
@ -25,11 +25,11 @@ CheckStackIsAligned:
|
|||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
|
||||
/ allocate sixteen bytes
|
||||
// allocate sixteen bytes
|
||||
push %rax
|
||||
push %rax
|
||||
|
||||
/ put a value in it
|
||||
// put a value in it
|
||||
xorps %xmm0,%xmm0
|
||||
movaps %xmm0,-16(%rbp)
|
||||
|
||||
|
|
|
@ -199,10 +199,11 @@ static int CloneXnu(int (*fn)(void *), char *stk, size_t stksz, int flags,
|
|||
wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid;
|
||||
wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid;
|
||||
wt->tls = flags & CLONE_SETTLS ? tls : 0;
|
||||
_seizelock(&wt->lock); // TODO: How can we get the tid without locking?
|
||||
wt->lock = 1;
|
||||
if ((rc = bsdthread_create(fn, arg, wt, 0, PTHREAD_START_CUSTOM_XNU)) != -1) {
|
||||
_spinlock(&wt->lock);
|
||||
rc = wt->tid;
|
||||
_spunlock(&wt->lock);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -263,9 +264,7 @@ static int CloneFreebsd(int (*func)(void *), char *stk, size_t stksz, int flags,
|
|||
// OPEN BESIYATA DISHMAYA
|
||||
|
||||
int __tfork(struct __tfork *params, size_t psize, struct CloneArgs *wt);
|
||||
asm(".section\t.privileged,\"ax\",@progbits\n\t"
|
||||
".local\t__tfork\n"
|
||||
"__tfork:\n\t"
|
||||
asm("__tfork:\n\t"
|
||||
"push\t$8\n\t"
|
||||
"pop\t%rax\n\t"
|
||||
"mov\t%rdx,%r8\n\t"
|
||||
|
@ -282,11 +281,10 @@ asm(".section\t.privileged,\"ax\",@progbits\n\t"
|
|||
"and\t$-16,%rsp\n\t"
|
||||
"push\t%rax\n\t"
|
||||
"jmp\tOpenbsdThreadMain\n\t"
|
||||
".size\t__tfork,.-__tfork\n\t"
|
||||
".previous");
|
||||
".size\t__tfork,.-__tfork\n\t");
|
||||
__attribute__((__used__, __no_reorder__))
|
||||
|
||||
static privileged wontreturn void
|
||||
static wontreturn void
|
||||
OpenbsdThreadMain(struct CloneArgs *wt) {
|
||||
wt->func(wt->arg);
|
||||
// we no longer use the stack after this point. however openbsd
|
||||
|
|
27
libc/runtime/getmemtracksize.c
Normal file
27
libc/runtime/getmemtracksize.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*-*- 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 2022 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 size_t GetMemtrackSize(struct MemoryIntervals *mm) {
|
||||
size_t i, n;
|
||||
for (n = i = 0; i < mm->i; ++i) {
|
||||
n += ((size_t)(mm->p[i].y - mm->p[i].x) + 1) << 16;
|
||||
}
|
||||
return n;
|
||||
}
|
|
@ -63,6 +63,7 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int,
|
|||
void (*)(struct MemoryIntervals *, int, int)) hidden;
|
||||
void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden;
|
||||
int UntrackMemoryIntervals(void *, size_t) hidden;
|
||||
size_t GetMemtrackSize(struct MemoryIntervals *);
|
||||
|
||||
#define IsLegalPointer(p) \
|
||||
(-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff)
|
||||
|
|
|
@ -148,14 +148,6 @@ noasan static bool Automap(int count, int align, int *res) {
|
|||
*res + count <= FRAME(kAutomapStart + (kAutomapSize - 1));
|
||||
}
|
||||
|
||||
noasan static size_t GetMemtrackSize(struct MemoryIntervals *mm) {
|
||||
size_t i, n;
|
||||
for (n = i = 0; i < mm->i; ++i) {
|
||||
n += ((size_t)(mm->p[i].y - mm->p[i].x) + 1) << 16;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static noasan void *FinishMemory(void *addr, size_t size, int prot, int flags,
|
||||
int fd, int64_t off, int f, int x, int n,
|
||||
struct DirectMap dm) {
|
||||
|
@ -491,10 +483,15 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
|||
noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
|
||||
int64_t off) {
|
||||
void *res;
|
||||
size_t toto;
|
||||
_spinlock(&_mmi.lock);
|
||||
res = Mmap(addr, size, prot, flags, fd, off);
|
||||
#if SYSDEBUG
|
||||
toto = __strace > 0 ? GetMemtrackSize(&_mmi) : 0;
|
||||
#endif
|
||||
_spunlock(&_mmi.lock);
|
||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m", addr, size,
|
||||
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res);
|
||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m (%'zu bytes total)", addr,
|
||||
size, DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res,
|
||||
toto);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -163,9 +163,13 @@ static noasan int Munmap(char *p, size_t n) {
|
|||
*/
|
||||
noasan int munmap(void *p, size_t n) {
|
||||
int rc;
|
||||
size_t toto;
|
||||
_spinlock(&_mmi.lock);
|
||||
rc = Munmap(p, n);
|
||||
#if SYSDEBUG
|
||||
toto = __strace > 0 ? GetMemtrackSize(&_mmi) : 0;
|
||||
#endif
|
||||
_spunlock(&_mmi.lock);
|
||||
STRACE("munmap(%.12p, %'zu) → %d% m", p, n, rc);
|
||||
STRACE("munmap(%.12p, %'zu) → %d% m (%'zu bytes total)", p, n, rc, toto);
|
||||
return rc;
|
||||
}
|
||||
|
|
2
libc/sysv/calls/__sys_gettid.s
Normal file
2
libc/sysv/calls/__sys_gettid.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_gettid,0x13712b1b0101b0ba,globl,hidden
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall break,0xffffff011fffffff,globl
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_gettid,0xfffffffff211e0ba,globl,hidden
|
|
@ -2054,7 +2054,7 @@ syscon nr __NR_modify_ldt 0x009a 0xfff 0xfff 0xfff 0xfff 0xfff
|
|||
syscon nr __NR_pivot_root 0x009b 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR__sysctl 0x009c 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_prctl 0x009d 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_arch_prctl 0x009e 0xfff 0x00a5 0x00a5 0xfff 0xfff
|
||||
syscon nr __NR_arch_prctl 0x009e 0x3000003 0x00a5 0x149 0x13d 0xfff # sysarch on freebsd, _lwp_setprivate on netbsd, __set_tcb on openbsd, thread_fast_set_cthread_self on xnu
|
||||
syscon nr __NR_adjtimex 0x009f 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_umount2 0x00a6 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_swapon 0x00a7 0x2000055 0x0055 0xfff 0xfff 0xfff
|
||||
|
@ -2065,7 +2065,7 @@ syscon nr __NR_iopl 0x00ac 0xfff 0xfff 0xfff 0xfff 0xfff
|
|||
syscon nr __NR_ioperm 0x00ad 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_init_module 0x00af 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_delete_module 0x00b0 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_gettid 0x00ba 0x200011e 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_gettid 0x00ba 0x0100001b 432 299 311 0xfff # TODO(jart): thread_self_trap vs. gettid?
|
||||
syscon nr __NR_readahead 0x00bb 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_setxattr 0x00bc 0x20000ec 0xfff 0xfff 0x177 0xfff
|
||||
syscon nr __NR_fsetxattr 0x00be 0x20000ed 0xfff 0xfff 0x179 0xfff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon termios,TIOCGPTN,0x80045430,0,0x4004740f,0,0,0
|
||||
.syscon pty,TIOCGPTN,0x80045430,0,0x4004740f,0,0,0
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon pty,TIOCSPTLCK,0x40045431,0,0,0,0,-1
|
||||
.syscon pty,TIOCSPTLCK,0x40045431,0,0,0,0,0
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon nr,__NR_arch_prctl,0x009e,0xfff,0x00a5,0x00a5,0xfff,0xfff
|
||||
.syscon nr,__NR_arch_prctl,0x009e,0x3000003,0x00a5,0x149,0x13d,0xfff
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon nr,__NR_gettid,0x00ba,0x200011e,0xfff,0xfff,0xfff,0xfff
|
||||
.syscon nr,__NR_gettid,0x00ba,0x0100001b,432,299,311,0xfff
|
||||
|
|
|
@ -219,7 +219,7 @@ scall iopl 0xfffffffffffff0ac globl
|
|||
scall ioperm 0xfffffffffffff0ad globl
|
||||
scall init_module 0xfffffffffffff0af globl
|
||||
scall delete_module 0xfffffffffffff0b0 globl
|
||||
scall sys_gettid 0xfffffffff211e0ba globl hidden
|
||||
scall __sys_gettid 0x13712b1b0101b0ba globl hidden # thread_self_trap (or gettid? on xnu), _lwp_self on netbsd, thr_self on freebsd, getthrid on openbsd
|
||||
scall readahead 0xfffffffffffff0bb globl # consider fadvise() / madvise()
|
||||
scall setxattr 0x177ffffff20ec0bc globl
|
||||
scall fsetxattr 0x179ffffff20ed0be globl
|
||||
|
@ -618,10 +618,10 @@ scall workq_open 0xfffffffff216ffff globl
|
|||
scall write_nocancel 0xfffffffff218dfff globl
|
||||
scall writev_nocancel 0xfffffffff219cfff globl
|
||||
#──────────────────────────FREEBSD───────────────────────────
|
||||
scall _umtx_op 0xffffff1c6fffffff globl
|
||||
scall abort2 0xffffff1cffffffff globl
|
||||
scall afs3_syscall 0xffffff179fffffff globl
|
||||
scall bindat 0xffffff21afffffff globl
|
||||
scall break 0xffffff011fffffff globl
|
||||
scall cap_enter 0xffffff204fffffff globl
|
||||
scall cap_fcntls_get 0xffffff219fffffff globl
|
||||
scall cap_fcntls_limit 0xffffff218fffffff globl
|
||||
|
@ -816,7 +816,6 @@ scall __acl_aclcheck_link 0xffffff1acfffffff globl
|
|||
scall __mac_syscall 0xfffffffff217dfff globl
|
||||
scall __acl_set_file 0xffffff15cfffffff globl
|
||||
scall __acl_delete_file 0xffffff15ffffffff globl
|
||||
scall _umtx_op 0xffffff1c6fffffff globl
|
||||
scall __semwait_signal_nocancel 0xfffffffff21a7fff globl
|
||||
scall __old_semwait_signal_nocancel 0xfffffffff2173fff globl
|
||||
scall sctp_peeloff 0xffffff1d7fffffff globl
|
||||
|
|
27
test/libc/nexgen32e/pcmpstr_test.c
Normal file
27
test/libc/nexgen32e/pcmpstr_test.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*-*- 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 2022 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/nexgen32e/nexgen32e.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
// pcmpestrm
|
||||
|
||||
/* TEST(pcmpstr, test) { */
|
||||
/* EXPECT_EQ(0, pcmpstr()); */
|
||||
/* EXPECT_STREQ("", pcmpstr()); */
|
||||
/* } */
|
|
@ -357,12 +357,7 @@ int count;
|
|||
void *ptrs[N];
|
||||
|
||||
void BenchUnmap(void) {
|
||||
int i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (ptrs[i]) {
|
||||
ASSERT_EQ(0, munmap(ptrs[i], FRAMESIZE));
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(0, munmap(ptrs[count++], FRAMESIZE));
|
||||
}
|
||||
|
||||
void BenchMmapPrivate(void) {
|
||||
|
@ -375,16 +370,11 @@ void BenchMmapPrivate(void) {
|
|||
|
||||
BENCH(mmap, bench) {
|
||||
EZBENCH2("mmap", donothing, BenchMmapPrivate());
|
||||
BenchUnmap();
|
||||
EZBENCH2("munmap", donothing, BenchUnmap());
|
||||
}
|
||||
|
||||
void BenchUnmapLinux(void) {
|
||||
int i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (ptrs[i]) {
|
||||
ASSERT_EQ(0, LinuxMunmap(ptrs[i], FRAMESIZE));
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(0, LinuxMunmap(ptrs[count++], FRAMESIZE));
|
||||
}
|
||||
|
||||
void BenchMmapPrivateLinux(void) {
|
||||
|
@ -399,5 +389,5 @@ BENCH(mmap, benchLinux) {
|
|||
void *p;
|
||||
if (!IsLinux()) return;
|
||||
EZBENCH2("mmap (linux)", donothing, BenchMmapPrivateLinux());
|
||||
BenchUnmapLinux();
|
||||
EZBENCH2("munmap (linux)", donothing, BenchUnmapLinux());
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@ noasan bool MemoryExists(char *p) {
|
|||
sigaction(SIGSEGV, &sa, old + 0);
|
||||
sigaction(SIGBUS, &sa, old + 1);
|
||||
c = atomic_load(p);
|
||||
sigaction(SIGSEGV, old + 0, 0);
|
||||
sigaction(SIGBUS, old + 1, 0);
|
||||
sigaction(SIGSEGV, old + 0, 0);
|
||||
return !gotsignal;
|
||||
}
|
||||
|
||||
|
|
|
@ -236,12 +236,6 @@ USAGE
|
|||
$ file redbean.com
|
||||
redbean.com: ELF 64-bit LSB executable
|
||||
|
||||
redbean contains software licensed ISC, MIT, BSD-2, BSD-3, zlib
|
||||
which makes it a permissively licensed gift to anyone who might
|
||||
find it useful. The transitive closure of legalese can be found
|
||||
inside the binary. redbean also respects your privacy and won't
|
||||
phone home because your computer is its home.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
SECURITY
|
||||
|
@ -1088,7 +1082,7 @@ FUNCTIONS
|
|||
ProgramPrivateKey(pem:str)
|
||||
Same as the -K flag if called from .init.lua, e.g.
|
||||
ProgramPrivateKey(LoadAsset("/.sign.key")) for zip loading or
|
||||
ProgramPrivateKey(Slurp("/etc/letsencrypt/fullchain.pem")) for
|
||||
ProgramPrivateKey(Slurp("/etc/letsencrypt/privkey.pem")) for
|
||||
local file system only.
|
||||
|
||||
ProgramRedirect(code:int,src:str,location:str)
|
||||
|
@ -4148,6 +4142,19 @@ UNIX MODULE
|
|||
reflects the value chosen by the underlying operating system.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
LEGAL
|
||||
|
||||
redbean contains software licensed ISC, MIT, BSD-2, BSD-3, zlib
|
||||
which makes it a permissively licensed gift to anyone who might
|
||||
find it useful. The transitive closure of legalese can be found
|
||||
inside the binary structure, because notice licenses require we
|
||||
distribute the license along with any software that uses it. By
|
||||
putting them in the binary, compliance in automated and no need
|
||||
for further action on the part of the user who is distributing.
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
SEE ALSO
|
||||
|
|
Loading…
Reference in a new issue