mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-12 05:59:10 +00:00
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:
parent
c6bbca55e9
commit
9208c83f7a
141 changed files with 1948 additions and 1411 deletions
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
.privileged
|
||||
|
||||
ftrace_hook:
|
||||
cmp $0,g_ftrace(%rip)
|
||||
cmp $0,__ftrace(%rip)
|
||||
jg 1f
|
||||
ret
|
||||
1: push %rbp
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
textstartup int ftrace_init(void) {
|
||||
if (__intercept_flag(&__argc, __argv, "--ftrace")) {
|
||||
ftrace_install();
|
||||
++g_ftrace;
|
||||
++__ftrace;
|
||||
}
|
||||
return __argc;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue