Make some systemic improvements

- add vdso dump utility
- tests now log stack usage
- rename g_ftrace to __ftrace
- make internal spinlocks go faster
- add conformant c11 atomics library
- function tracing now logs stack usage
- make function call tracing thread safe
- add -X unsecure (no ssl) mode to redbean
- munmap() has more consistent behavior now
- pacify fsync() calls on python unit tests
- make --strace flag work better in redbean
- start minimizing and documenting compiler flags
This commit is contained in:
Justine Tunney 2022-05-18 16:41:29 -07:00
parent c6bbca55e9
commit 9208c83f7a
141 changed files with 1948 additions and 1411 deletions

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/memtrack.internal.h"
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
@ -27,6 +28,12 @@ noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
STRACE("AreMemoryIntervalsOk() y should be >= x!");
return false;
}
if (!(mm->p[i].size <=
(size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE + FRAMESIZE &&
mm->p[i].size > (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE)) {
STRACE("AreMemoryIntervalsOk() size is wrong!");
return false;
}
if (i) {
if (mm->p[i].h != -1 || mm->p[i - 1].h != -1) {
if (mm->p[i].x <= mm->p[i - 1].y) {

View file

@ -45,7 +45,6 @@
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
@ -222,7 +221,6 @@ textwindows void WinMainForked(void) {
// rewrap the stdin named pipe hack
// since the handles closed on fork
if (weaken(ForkNtStdinWorker)) weaken(ForkNtStdinWorker)();
struct Fds *fds = VEIL("r", &g_fds);
fds->p[0].handle = fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle);
fds->p[1].handle = fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle);

View file

@ -20,7 +20,7 @@
.privileged
ftrace_hook:
cmp $0,g_ftrace(%rip)
cmp $0,__ftrace(%rip)
jg 1f
ret
1: push %rbp

View file

@ -35,7 +35,7 @@
textstartup int ftrace_init(void) {
if (__intercept_flag(&__argc, __argv, "--ftrace")) {
ftrace_install();
++g_ftrace;
++__ftrace;
}
return __argc;
}

View file

@ -17,24 +17,26 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/rdtscp.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/clockstonanos.internal.h"
#pragma weak stderr
#define MAX_NESTING 512
/**
@ -47,13 +49,16 @@
void ftrace_hook(void);
bool ftrace_enabled;
static int g_skew;
static int64_t g_lastaddr;
static uint64_t g_laststamp;
_Alignas(64) char ftrace_lock;
static privileged noinstrument noasan noubsan int GetNestingLevelImpl(
struct StackFrame *frame) {
static struct Ftrace {
int skew;
int stackdigs;
int64_t lastaddr;
uint64_t laststamp;
} g_ftrace;
static privileged int GetNestingLevelImpl(struct StackFrame *frame) {
int nesting = -2;
while (frame) {
++nesting;
@ -62,12 +67,11 @@ static privileged noinstrument noasan noubsan int GetNestingLevelImpl(
return MAX(0, nesting);
}
static privileged noinstrument noasan noubsan int GetNestingLevel(
struct StackFrame *frame) {
static privileged int GetNestingLevel(struct StackFrame *frame) {
int nesting;
nesting = GetNestingLevelImpl(frame);
if (nesting < g_skew) g_skew = nesting;
nesting -= g_skew;
if (nesting < g_ftrace.skew) g_ftrace.skew = nesting;
nesting -= g_ftrace.skew;
return MIN(MAX_NESTING, nesting);
}
@ -78,32 +82,30 @@ static privileged noinstrument noasan noubsan int GetNestingLevel(
* prologues of other functions. We assume those functions behave
* according to the System Five NexGen32e ABI.
*/
privileged noinstrument noasan noubsan void ftracer(void) {
/* asan runtime depends on this function */
privileged void ftracer(void) {
uint64_t stamp;
static bool noreentry;
size_t stackuse;
struct StackFrame *frame;
if (!_cmpxchg(&noreentry, 0, 1)) return;
if (ftrace_enabled) {
stamp = rdtsc();
frame = __builtin_frame_address(0);
frame = frame->next;
if (frame->addr != g_lastaddr) {
kprintf("%rFUN %5P %'18T %*s%t\r\n", GetNestingLevel(frame) * 2, "",
frame->addr);
g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
g_lastaddr = frame->addr;
}
_spinlock_cooperative(&ftrace_lock);
stamp = rdtsc();
frame = __builtin_frame_address(0);
frame = frame->next;
if (frame->addr != g_ftrace.lastaddr) {
stackuse = ROUNDUP((intptr_t)frame, GetStackSize()) - (intptr_t)frame;
kprintf("%rFUN %5P %'13T %'*lu %*s%t\r\n", g_ftrace.stackdigs, stackuse,
GetNestingLevel(frame) * 2, "", frame->addr);
g_ftrace.laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
g_ftrace.lastaddr = frame->addr;
}
noreentry = 0;
_spunlock(&ftrace_lock);
}
textstartup int ftrace_install(void) {
if (GetSymbolTable()) {
g_lastaddr = -1;
g_laststamp = kStartTsc;
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
ftrace_enabled = 1;
g_ftrace.lastaddr = -1;
g_ftrace.laststamp = kStartTsc;
g_ftrace.stackdigs = LengthInt64Thousands(GetStackSize());
g_ftrace.skew = GetNestingLevelImpl(__builtin_frame_address(0));
return __hook(ftrace_hook, GetSymbolTable());
} else {
kprintf("error: --ftrace failed to open symbol table\r\n");

View file

@ -26,6 +26,7 @@
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/directmap.internal.h"
@ -112,7 +113,9 @@ int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
if (CreateMemoryInterval(mm, i) == -1) return -1;
mm->p[i].y = x - 1;
mm->p[i + 0].size -= (size_t)(mm->p[i + 0].y - (x - 1)) * FRAMESIZE;
mm->p[i + 0].y = x - 1;
mm->p[i + 1].size -= (size_t)((y + 1) - mm->p[i + 1].x) * FRAMESIZE;
mm->p[i + 1].x = y + 1;
return 0;
}
@ -123,31 +126,60 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
assert(y >= x);
assert(AreMemoryIntervalsOk(mm));
if (!mm->i) return 0;
// binary search for the lefthand side
l = FindMemoryInterval(mm, x);
if (l == mm->i) return 0;
if (!l && y < mm->p[l].x) return 0;
if (y < mm->p[l].x) return 0;
// binary search for the righthand side
r = FindMemoryInterval(mm, y);
if (r == mm->i || (r > l && y < mm->p[r].x)) --r;
assert(r >= l);
assert(x <= mm->p[r].y);
// remove the middle of an existing map
//
// ----|mmmmmmmmmmmmmmmm|--------- before
// xxxxx
// ----|mmmm|-----|mmmmm|--------- after
//
// this isn't possible on windows because we track each
// 64kb segment on that platform using a separate entry
if (l == r && x > mm->p[l].x && y < mm->p[l].y) {
return PunchHole(mm, x, y, l);
}
// trim the right side of the lefthand map
//
// ----|mmmmmmm|-------------- before
// xxxxx
// ----|mmmm|----------------- after
//
if (x > mm->p[l].x && x <= mm->p[l].y) {
assert(y >= mm->p[l].y);
if (IsWindows()) return einval();
mm->p[l].size -= (size_t)(mm->p[l].y - (x - 1)) * FRAMESIZE;
mm->p[l].y = x - 1;
assert(mm->p[l].x <= mm->p[l].y);
++l;
}
// trim the left side of the righthand map
//
// ------------|mmmmm|-------- before
// xxxxx
// ---------------|mm|-------- after
//
if (y >= mm->p[r].x && y < mm->p[r].y) {
assert(x <= mm->p[r].x);
if (IsWindows()) return einval();
mm->p[r].size -= (size_t)((y + 1) - mm->p[r].x) * FRAMESIZE;
mm->p[r].x = y + 1;
assert(mm->p[r].x <= mm->p[r].y);
--r;
}
if (l <= r) {
if (IsWindows() && wf) {
wf(mm, l, r);
@ -164,19 +196,38 @@ int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
unsigned i;
assert(y >= x);
assert(AreMemoryIntervalsOk(mm));
i = FindMemoryInterval(mm, x);
// try to extend the righthand side of the lefthand entry
// we can't do that if we're tracking independent handles
// we can't do that if it's a file map with a small size!
if (i && x == mm->p[i - 1].y + 1 && h == mm->p[i - 1].h &&
prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags) {
prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags &&
mm->p[i - 1].size ==
(size_t)(mm->p[i - 1].y - mm->p[i - 1].x) * FRAMESIZE + FRAMESIZE) {
mm->p[i - 1].size += (size_t)(y - mm->p[i - 1].y) * FRAMESIZE;
mm->p[i - 1].y = y;
// if we filled the hole then merge the two mappings
if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h &&
prot == mm->p[i].prot && flags == mm->p[i].flags) {
mm->p[i - 1].y = mm->p[i].y;
mm->p[i - 1].size += mm->p[i].size;
RemoveMemoryIntervals(mm, i, 1);
}
} else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h &&
prot == mm->p[i].prot && flags == mm->p[i].flags) {
}
// try to extend the lefthand side of the righthand entry
// we can't do that if we're creating a smaller file map!
else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h &&
prot == mm->p[i].prot && flags == mm->p[i].flags &&
size == (size_t)(y - x) * FRAMESIZE + FRAMESIZE) {
mm->p[i].size += (size_t)(mm->p[i].x - x) * FRAMESIZE;
mm->p[i].x = x;
} else {
}
// otherwise, create a new entry and memmove the items
else {
if (CreateMemoryInterval(mm, i) == -1) return -1;
mm->p[i].x = x;
mm->p[i].y = y;

View file

@ -34,10 +34,10 @@ struct MemoryInterval {
int x;
int y;
long h;
long size;
int prot;
int flags;
long offset;
long size;
bool iscow;
bool readonlyfile;
};
@ -90,25 +90,27 @@ forceinline pureconst bool IsShadowFrame(int x) {
}
forceinline pureconst bool IsKernelFrame(int x) {
return (int)(GetStaticStackAddr(0) >> 16) <= x &&
x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >>
16);
intptr_t stack = (intptr_t)GetStaticStackAddr(0);
return (int)(stack >> 16) <= x &&
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsStaticStackFrame(int x) {
return (int)(GetStaticStackAddr(0) >> 16) <= x &&
x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >>
16);
intptr_t stack = (intptr_t)GetStaticStackAddr(0);
return (int)(stack >> 16) <= x &&
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsStackFrame(int x) {
return (int)(GetStackAddr(0) >> 16) <= x &&
x <= (int)((GetStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16);
intptr_t stack = (intptr_t)GetStackAddr(0);
return (int)(stack >> 16) <= x &&
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsSigAltStackFrame(int x) {
return (int)(GetStackAddr(0) >> 16) <= x &&
x <= (int)((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16);
intptr_t stack = (intptr_t)GetStackAddr(0);
return (int)(stack >> 16) <= x &&
x <= (int)((stack + (SIGSTKSZ - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsOldStackFrame(int x) {

View file

@ -16,16 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
@ -36,89 +42,123 @@
#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16)
#define FRAME(x) ((int)((intptr_t)(x) >> 16))
static noasan int Munmap(void *v, size_t n) {
char poison, *p = v;
static noasan int Munmap(char *, size_t);
static noasan void MunmapShadow(char *p, size_t n) {
intptr_t a, b, x, y;
KERNTRACE("MunmapShadow(%p, %'zu)", p, n);
a = ((intptr_t)p >> 3) + 0x7fff8000;
b = a + (n >> 3);
if (IsMemtracked(FRAME(a), FRAME(b - 1))) {
x = ROUNDUP(a, FRAMESIZE);
y = ROUNDDOWN(b, FRAMESIZE);
if (0 && x < y) {
// delete shadowspace if unmapping ≥512kb. in practice it has
// to be >1mb since we can only unmap it if it's aligned, and
// as such we poison the edges if there are any.
__repstosb((void *)a, kAsanUnmapped, x - a);
Munmap((void *)x, y - x);
__repstosb((void *)y, kAsanUnmapped, b - y);
} else {
// otherwise just poison and assume reuse
__repstosb((void *)a, kAsanUnmapped, b - a);
}
} else {
STRACE("unshadow(%.12p, %p) EFAULT", a, b - a);
}
}
// our api supports doing things like munmap(0, 0x7fffffffffff) but some
// platforms (e.g. openbsd) require that we know the specific intervals
// or else it returns EINVAL. so we munmap a piecewise.
static noasan void MunmapImpl(char *p, size_t n) {
char *q;
size_t m;
intptr_t a, b, c;
int i, l, r, rc, beg, end;
KERNTRACE("MunmapImpl(%p, %'zu)", p, n);
l = FRAME(p);
r = FRAME(p + n - 1);
i = FindMemoryInterval(&_mmi, l);
for (; i < _mmi.i && r >= _mmi.p[i].x; ++i) {
if (l >= _mmi.p[i].x && r <= _mmi.p[i].y) {
// it's contained within the entry
beg = l;
end = r;
} else if (l <= _mmi.p[i].x && r >= _mmi.p[i].x) {
// it overlaps with the lefthand side of the entry
beg = _mmi.p[i].x;
end = MIN(r, _mmi.p[i].y);
} else if (l <= _mmi.p[i].y && r >= _mmi.p[i].y) {
// it overlaps with the righthand side of the entry
beg = MAX(_mmi.p[i].x, l);
end = _mmi.p[i].y;
} else {
// shouldn't be possible
assert(!"binary search panic");
continue;
}
// openbsd even requires that if we mapped, for instance a 5 byte
// file, that we be sure to call munmap(file, 5). let's abstract!
a = ADDR(beg);
b = ADDR(end) + FRAMESIZE;
c = ADDR(_mmi.p[i].x) + _mmi.p[i].size;
q = (char *)a;
m = MIN(b, c) - a;
if (!IsWindows()) {
rc = sys_munmap(q, m);
assert(!rc);
} else {
// Handled by UntrackMemoryIntervals() on Windows
}
if (IsAsan() && !OverlapsShadowSpace(p, n)) {
MunmapShadow(q, m);
}
}
}
static noasan int Munmap(char *p, size_t n) {
unsigned i;
char poison;
intptr_t a, b, x, y;
assert(!__vforked);
if (UNLIKELY(!n)) {
STRACE("munmap(%.12p, %'zu) %s (n=0)", p, n);
STRACE("munmap(%.12p, %'zu) EINVAL (n=0)", p, n);
return einval();
}
if (UNLIKELY(!IsLegalSize(n))) {
STRACE("munmap(%.12p, %'zu) EINVAL (n isn't 48-bit)", p, n);
return einval();
}
if (UNLIKELY(!IsLegalPointer(p))) {
STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, n);
return einval();
}
if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) {
STRACE("munmap(%.12p, %'zu) EINVAL (p+(n-1) isn't 48-bit)", p, n);
return einval();
}
if (UNLIKELY(!ALIGNED(p))) {
STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, n);
return einval();
}
if (!IsMemtracked(FRAME(p), FRAME(p + (n - 1)))) {
STRACE("munmap(%.12p, %'zu) EFAULT (interval not tracked)", p, n);
return efault();
}
if (UntrackMemoryIntervals(p, n) == -1) {
return -1;
}
if (IsWindows()) {
return 0; // UntrackMemoryIntervals does it for NT
}
if (sys_munmap(p, n) == -1) {
return -1; // ouch
}
if (IsAsan() && !OverlapsShadowSpace(p, n)) {
a = ((intptr_t)p >> 3) + 0x7fff8000;
b = a + (n >> 3);
if (IsMemtracked(FRAME(a), FRAME(b - 1))) {
x = ROUNDUP(a, FRAMESIZE);
y = ROUNDDOWN(b, FRAMESIZE);
if (x < y) {
// delete shadowspace if unmapping ≥512kb
__repstosb((void *)a, kAsanUnmapped, x - a);
Munmap((void *)x, y - x);
__repstosb((void *)y, kAsanUnmapped, b - y);
} else {
// otherwise just poison and assume reuse
__repstosb((void *)a, kAsanUnmapped, b - a);
}
} else {
STRACE("unshadow(%.12p, %p) EFAULT", a, b - a);
}
}
return 0;
MunmapImpl(p, n);
return UntrackMemoryIntervals(p, n);
}
/**
* Releases memory pages.
*
* This function may be used to punch holes in existing mappings, but
* your mileage may vary on Windows.
*
* @param p is a pointer within any memory mapped region the process
* has permission to control, such as address ranges returned by
* mmap(), the program image itself, etc.
* @param n is the number of bytes to be unmapped, and needs to be a
* multiple of FRAMESIZE for anonymous mappings, because windows
* and for files size needs to be perfect to the byte bc openbsd
* @param p is the beginning of the memory region to unmap
* @param n is the number of bytes to be unmapped
* @return 0 on success, or -1 w/ errno
* @raises EINVAL if `n == 0`
* @raises EINVAL if `n` isn't 48-bit
* @raises EINVAL if `p+(n-1)` isn't 48-bit
* @raises EINVAL if `p` isn't 65536-byte aligned
*/
noasan int munmap(void *p, size_t n) {
int rc;

View file

@ -147,8 +147,8 @@ textstartup void __printargs(const char *prologue) {
struct pollfd pfds[128];
} u;
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED);
__atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED);
--__ftrace;
--__strace;
e = errno;
PRINT("");
@ -547,7 +547,7 @@ textstartup void __printargs(const char *prologue) {
}
PRINT("");
__atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED);
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED);
++__strace;
++__ftrace;
errno = e;
}

View file

@ -41,10 +41,16 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
for (i = 0; i < mm->i; ++i) {
frames = mm->p[i].y + 1 - mm->p[i].x;
maptally += frames;
kprintf("%012lx-%012lx %s %'*ldx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1),
kprintf("%08x-%08x %s %'*ldx%s", mm->p[i].x, mm->p[i].y,
DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
DescribeFrame(mm->p[i].x));
if (i + 1 < _mmi.i) {
if (mm->p[i].iscow) kprintf(" cow");
if (mm->p[i].readonlyfile) kprintf(" readonlyfile");
if (mm->p[i].size !=
(size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE + FRAMESIZE) {
kprintf(" size=%'zu", mm->p[i].size);
}
if (i + 1 < mm->i) {
frames = mm->p[i + 1].x - mm->p[i].y - 1;
if (frames && IsNoteworthyHole(i, mm)) {
gaptally += frames;

View file

@ -14,10 +14,12 @@ extern char **__argv; /* CRT */
extern char **__envp; /* CRT */
extern unsigned long *__auxv; /* CRT */
extern intptr_t __oldstack; /* CRT */
extern uint64_t __nosync; /* SYS */
extern _Atomic(int) __ftrace; /* SYS */
extern _Atomic(int) __strace; /* SYS */
extern char *program_invocation_name; /* RII */
extern char *program_invocation_short_name; /* RII */
extern int g_ftrace; /* CRT */
extern uint64_t g_syscount; /* RII */
extern uint64_t __syscount; /* RII */
extern const uint64_t kStartTsc; /* RII */
extern const char kTmpPath[]; /* RII */
extern const char kNtSystemDirectory[]; /* RII */
@ -38,7 +40,6 @@ extern unsigned char *__relo_start[]; /* αpε */
extern unsigned char *__relo_end[]; /* αpε */
extern uint8_t __zip_start[]; /* αpε */
extern uint8_t __zip_end[]; /* αpε */
extern bool ftrace_enabled;
extern size_t __virtualmax;
extern bool __isworker;

View file

@ -58,24 +58,25 @@ $(LIBC_RUNTIME_A).pkg: \
$(LIBC_RUNTIME_A_OBJS) \
$(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x)_A).pkg)
# we can't use asan and ubsan because:
# asan and ubsan can be function traced
# we can't use function tracing because:
# this is the function tracing runtime
o/$(MODE)/libc/runtime/ftracer.o: \
OVERRIDE_CFLAGS += \
-mno-fentry \
-ffreestanding \
-fno-sanitize=all
o/$(MODE)/libc/runtime/fork-nt.o \
o/$(MODE)/libc/runtime/printmemoryintervals.o \
o/$(MODE)/libc/runtime/arememoryintervalsok.o \
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/sys_mprotect.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 \
o/$(MODE)/libc/runtime/morph.greg.o \
o/$(MODE)/libc/runtime/mprotect.greg.o \
o/$(MODE)/libc/runtime/mprotect-nt.greg.o \
o/$(MODE)/libc/runtime/ismemtracked.greg.o \
o/$(MODE)/libc/runtime/isheap.o \
o/$(MODE)/libc/runtime/memtracknt.o \
o/$(MODE)/libc/runtime/memtrack.greg.o \
o/$(MODE)/libc/runtime/metalprintf.greg.o \

View file

@ -61,8 +61,9 @@ extern char ape_stack_align[] __attribute__((__weak__));
/**
* Returns address of bottom of stack.
*/
#define GetStackAddr(ADDEND) \
((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + (ADDEND))
#define GetStackAddr(ADDEND) \
((void *)((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + \
(ADDEND)))
/**
* Returns preferred bottom address of stack.
@ -78,7 +79,7 @@ extern char ape_stack_align[] __attribute__((__weak__));
} else { \
vAddr = 0x10000000; \
} \
vAddr; \
(void *)vAddr; \
})
COSMOPOLITAN_C_END_

View file

@ -16,9 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
@ -26,16 +29,23 @@
static char stacklog[1024];
static size_t NullLength(const char *s) {
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
size_t n;
xmm_t v, z = {0};
unsigned m, k = (uintptr_t)s & 15;
const xmm_t *p = (const xmm_t *)((uintptr_t)s & -16);
m = (__builtin_ia32_pmovmskb128(*p == z) ^ 0xffff) >> k << k;
while (!m) m = __builtin_ia32_pmovmskb128(*++p == z) ^ 0xffff;
n = (const char *)p + __builtin_ctzl(m) - s;
return n;
size_t GetStackUsage(char *s, size_t n) {
// RHEL5 MAP_GROWSDOWN seems to only grow to 68kb :'(
// So we count non-zero bytes down from the top
// First clear 64 bytes is considered the end
long *p;
size_t got;
p = (long *)(s + n);
got = 0;
for (;;) {
p -= 8;
if (p[0] | p[1] | p[2] | p[3] | p[4] | p[5] | p[6] | p[7]) {
++got;
} else {
break;
}
}
return got * 8 * sizeof(long);
}
static textexit void LogStackUse(void) {
@ -43,10 +53,8 @@ static textexit void LogStackUse(void) {
bool quote;
char *p, *q;
size_t n, usage;
const char *stack;
usage = GetStackUsage(GetStackAddr(0), GetStackSize());
fd = open(stacklog, O_APPEND | O_CREAT | O_WRONLY, 0644);
stack = (char *)GetStackAddr(0);
usage = GetStackSize() - (NullLength(stack + PAGESIZE) + PAGESIZE);
p = FormatUint64(stacklog, usage);
for (i = 0; i < __argc; ++i) {
n = strlen(__argv[i]);

View file

@ -16,17 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/runtime/memtrack.internal.h"
int UntrackMemoryIntervals(void *addr, size_t size) {
int a, b;
assert(size > 0);
a = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16;
b = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16;
if (SupportsWindows()) {
return ReleaseMemoryIntervals(&_mmi, a, b, ReleaseMemoryNt);
} else {
return ReleaseMemoryIntervals(&_mmi, a, b, 0);
}
return ReleaseMemoryIntervals(&_mmi, a, b,
SupportsWindows() ? ReleaseMemoryNt : 0);
}

View file

@ -198,7 +198,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
_mmi.p = _mmi.s;
_mmi.n = ARRAYLEN(_mmi.s);
argsize = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE);
stackaddr = GetStaticStackAddr(0);
stackaddr = (intptr_t)GetStaticStackAddr(0);
stacksize = GetStackSize();
allocsize = argsize + stacksize;
allocaddr = stackaddr - argsize;