mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 23:13:34 +00:00
a359de7893
This changes *NSYNC to allocate waiters on the stack so our locks don't need to depend on dynamic memory. This make our runtiem simpler, and it also fixes bugs with thread cancellation support.
196 lines
6 KiB
C
196 lines
6 KiB
C
#ifndef COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_
|
|
#define COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_
|
|
#include "ape/sections.internal.h"
|
|
#include "libc/dce.h"
|
|
#include "libc/intrin/nopl.internal.h"
|
|
#include "libc/macros.internal.h"
|
|
#include "libc/nt/version.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/runtime/stack.h"
|
|
#include "libc/sysv/consts/ss.h"
|
|
#include "libc/thread/tls.h"
|
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
|
COSMOPOLITAN_C_START_
|
|
|
|
#define kAutomapStart 0x100080040000
|
|
#define kAutomapSize (kMemtrackStart - kAutomapStart)
|
|
#define kMemtrackStart 0x1fe7fffc0000
|
|
#define kMemtrackSize (0x1ffffffc0000 - kMemtrackStart)
|
|
#define kFixedmapStart 0x300000040000
|
|
#define kFixedmapSize (0x400000040000 - kFixedmapStart)
|
|
#define kMemtrackFdsStart 0x6fe000040000
|
|
#define kMemtrackFdsSize (0x6feffffc0000 - kMemtrackFdsStart)
|
|
#define kMemtrackZiposStart 0x6fd000040000
|
|
#define kMemtrackZiposSize (0x6fdffffc0000 - kMemtrackZiposStart)
|
|
#define kMemtrackGran (!IsAsan() ? FRAMESIZE : FRAMESIZE * 8)
|
|
|
|
struct MemoryInterval {
|
|
int x;
|
|
int y;
|
|
long h;
|
|
long size;
|
|
long offset;
|
|
int flags;
|
|
char prot;
|
|
bool iscow;
|
|
bool readonlyfile;
|
|
};
|
|
|
|
struct MemoryIntervals {
|
|
size_t i, n;
|
|
struct MemoryInterval *p;
|
|
struct MemoryInterval s[16];
|
|
};
|
|
|
|
extern struct MemoryIntervals _mmi;
|
|
|
|
void __mmi_init(void);
|
|
void __mmi_lock(void);
|
|
void __mmi_unlock(void);
|
|
void __mmi_funlock(void);
|
|
bool IsMemtracked(int, int);
|
|
void PrintSystemMappings(int);
|
|
unsigned __find_memory(const struct MemoryIntervals *, int) nosideeffect;
|
|
bool __check_memtrack(const struct MemoryIntervals *) nosideeffect;
|
|
void PrintMemoryIntervals(int, const struct MemoryIntervals *);
|
|
int __track_memory(struct MemoryIntervals *, int, int, long, int, int, bool,
|
|
bool, long, long);
|
|
int __untrack_memory(struct MemoryIntervals *, int, int,
|
|
void (*)(struct MemoryIntervals *, int, int));
|
|
void __release_memory_nt(struct MemoryIntervals *, int, int);
|
|
int __untrack_memories(void *, size_t);
|
|
size_t __get_memtrack_size(struct MemoryIntervals *);
|
|
|
|
#ifdef _NOPL0
|
|
#define __mmi_lock() _NOPL0("__threadcalls", __mmi_lock)
|
|
#define __mmi_unlock() _NOPL0("__threadcalls", __mmi_unlock)
|
|
#else
|
|
#define __mmi_lock() (__threaded ? __mmi_lock() : 0)
|
|
#define __mmi_unlock() (__threaded ? __mmi_unlock() : 0)
|
|
#endif
|
|
|
|
#ifdef __x86_64__
|
|
/*
|
|
* AMD64 has 48-bit signed pointers (PML4T)
|
|
* AMD64 is trying to go bigger, i.e. 57-bit (PML5T)
|
|
* LINUX forbids userspace from leveraging negative pointers
|
|
* Q-EMU may impose smaller vaspaces emulating AMD on non-AMD
|
|
*
|
|
* Having "signed pointers" means these top sixteen bits
|
|
*
|
|
* 0x0000000000000000
|
|
* ^^^^
|
|
*
|
|
* must be
|
|
*
|
|
* - 0000 for positive pointers
|
|
* - FFFF for negative pointers
|
|
*
|
|
* otherwise the instruction using the faulty pointer will fault.
|
|
*/
|
|
#define IsLegalPointer(p) \
|
|
(-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff)
|
|
#define ADDR_32_TO_48(x) (intptr_t)((uint64_t)(int)(x) << 16)
|
|
#elif defined(__aarch64__)
|
|
/*
|
|
* ARM64 has 48-bit unsigned pointers (Armv8.0-A)
|
|
* ARM64 can possibly go bigger, i.e. 52-bit (Armv8.2-A)
|
|
* ARM64 can impose arbitrarily smaller vaspaces, e.g. 40/44-bit
|
|
* APPLE in their limitless authoritarianism forbids 32-bit pointers
|
|
*/
|
|
#define IsLegalPointer(p) ((uintptr_t)(p) <= 0xffffffffffff)
|
|
#define ADDR_32_TO_48(x) (uintptr_t)((uint64_t)(uint32_t)(x) << 16)
|
|
#else
|
|
/* RISC-V Sipeed Nezha has 39-bit vaspace */
|
|
#error "unsupported architecture"
|
|
#endif
|
|
|
|
forceinline pureconst bool IsLegalSize(uint64_t n) {
|
|
/* subtract frame size so roundup is safe */
|
|
return n <= 0x800000000000 - FRAMESIZE;
|
|
}
|
|
|
|
forceinline pureconst bool IsAutoFrame(int x) {
|
|
return (int)(kAutomapStart >> 16) <= x &&
|
|
x <= (int)((kAutomapStart + kAutomapSize - 1) >> 16);
|
|
}
|
|
|
|
forceinline pureconst bool IsMemtrackFrame(int x) {
|
|
return (int)(kAutomapStart >> 16) <= x &&
|
|
x <= (int)((kAutomapStart + kAutomapSize - 1) >> 16);
|
|
}
|
|
|
|
forceinline pureconst bool IsGfdsFrame(int x) {
|
|
return (int)(kMemtrackFdsStart >> 16) <= x &&
|
|
x <= (int)((kMemtrackFdsStart + kMemtrackFdsSize - 1) >> 16);
|
|
}
|
|
|
|
forceinline pureconst bool IsZiposFrame(int x) {
|
|
return (int)(kMemtrackZiposStart >> 16) <= x &&
|
|
x <= (int)((kMemtrackZiposStart + kMemtrackZiposSize - 1) >> 16);
|
|
}
|
|
|
|
forceinline pureconst bool IsShadowFrame(int x) {
|
|
return 0x7fff <= x && x < 0x10008000;
|
|
}
|
|
|
|
forceinline pureconst bool IsStaticStackFrame(int x) {
|
|
intptr_t stack = GetStaticStackAddr(0);
|
|
return (int)(stack >> 16) <= x &&
|
|
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
|
}
|
|
|
|
forceinline pureconst bool IsStackFrame(int x) {
|
|
intptr_t stack = GetStackAddr();
|
|
return (int)(stack >> 16) <= x &&
|
|
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
|
}
|
|
|
|
forceinline pureconst bool IsOldStack(const void *x) {
|
|
size_t foss_stack_size = 8ul * 1024 * 1024;
|
|
uintptr_t top = __oldstack + foss_stack_size;
|
|
uintptr_t bot = __oldstack - foss_stack_size;
|
|
return bot <= (uintptr_t)x && (uintptr_t)x < top;
|
|
}
|
|
|
|
forceinline pureconst bool IsOldStackFrame(int x) {
|
|
size_t foss_stack_size = 8ul * 1024 * 1024;
|
|
uintptr_t top = __oldstack + foss_stack_size;
|
|
uintptr_t bot = __oldstack - foss_stack_size;
|
|
return (int)(bot >> 16) <= x && x <= (int)((top >> 16) - 1);
|
|
}
|
|
|
|
forceinline pureconst bool IsFixedFrame(int x) {
|
|
return (kFixedmapStart >> 16) <= x &&
|
|
x <= ((kFixedmapStart + (kFixedmapSize - 1)) >> 16);
|
|
}
|
|
|
|
forceinline pureconst bool OverlapsImageSpace(const void *p, size_t n) {
|
|
const unsigned char *BegA, *EndA, *BegB, *EndB;
|
|
if (n) {
|
|
BegA = p;
|
|
EndA = BegA + (n - 1);
|
|
BegB = __executable_start;
|
|
EndB = _end - 1;
|
|
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
forceinline pureconst bool OverlapsShadowSpace(const void *p, size_t n) {
|
|
intptr_t BegA, EndA, BegB, EndB;
|
|
if (n) {
|
|
BegA = (intptr_t)p;
|
|
EndA = BegA + (n - 1);
|
|
BegB = 0x7fff0000;
|
|
EndB = 0x10007fffffff;
|
|
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
COSMOPOLITAN_C_END_
|
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
|
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_ */
|