mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 03:08:31 +00:00
Make numerous improvements
- Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
This commit is contained in:
parent
fa7b4f5bd1
commit
39bf41f4eb
806 changed files with 77494 additions and 63859 deletions
|
@ -16,85 +16,69 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
|
||||
/**
|
||||
* Sets memory.
|
||||
* Returns population count of array.
|
||||
*
|
||||
* @param p is memory address
|
||||
* @param c is masked with 255 and used as repeated byte
|
||||
* @param n is byte length
|
||||
* @return p
|
||||
* @asyncsignalsafe
|
||||
* @param a is byte sequence
|
||||
* @return number of bits set to one
|
||||
* @note 30gbps on Nehalem (Intel 2008+) otherwise 3gbps
|
||||
*/
|
||||
void *memset_pure(void *p, int c, size_t n) {
|
||||
char *b;
|
||||
size_t _countbits(const void *a, size_t n) {
|
||||
int i;
|
||||
size_t t;
|
||||
unsigned b;
|
||||
uint64_t x;
|
||||
b = p;
|
||||
x = 0x0101010101010101ul * (c & 0xff);
|
||||
switch (n) {
|
||||
case 0:
|
||||
return p;
|
||||
case 1:
|
||||
__builtin_memcpy(b, &x, 1);
|
||||
return p;
|
||||
case 2:
|
||||
__builtin_memcpy(b, &x, 2);
|
||||
return p;
|
||||
case 3:
|
||||
__builtin_memcpy(b, &x, 2);
|
||||
__builtin_memcpy(b + 1, &x, 2);
|
||||
return p;
|
||||
case 4:
|
||||
__builtin_memcpy(b, &x, 4);
|
||||
return p;
|
||||
case 5 ... 7:
|
||||
__builtin_memcpy(b, &x, 4);
|
||||
__builtin_memcpy(b + n - 4, &x, 4);
|
||||
return p;
|
||||
case 8:
|
||||
__builtin_memcpy(b, &x, 8);
|
||||
return p;
|
||||
case 9 ... 16:
|
||||
__builtin_memcpy(b, &x, 8);
|
||||
__builtin_memcpy(b + n - 8, &x, 8);
|
||||
return p;
|
||||
default:
|
||||
do {
|
||||
n -= 16;
|
||||
__builtin_memcpy(b + n, &x, 8);
|
||||
asm volatile("" ::: "memory");
|
||||
__builtin_memcpy(b + n + 8, &x, 8);
|
||||
} while (n >= 16);
|
||||
switch (n) {
|
||||
case 0:
|
||||
return p;
|
||||
case 1:
|
||||
__builtin_memcpy(b, &x, 1);
|
||||
return p;
|
||||
case 2:
|
||||
__builtin_memcpy(b, &x, 2);
|
||||
return p;
|
||||
case 3:
|
||||
__builtin_memcpy(b, &x, 2);
|
||||
__builtin_memcpy(b + 1, &x, 2);
|
||||
return p;
|
||||
case 4:
|
||||
__builtin_memcpy(b, &x, 4);
|
||||
return p;
|
||||
case 5 ... 7:
|
||||
__builtin_memcpy(b, &x, 4);
|
||||
__builtin_memcpy(b + n - 4, &x, 4);
|
||||
return p;
|
||||
case 8:
|
||||
__builtin_memcpy(b, &x, 8);
|
||||
return p;
|
||||
case 9 ... 15:
|
||||
__builtin_memcpy(b, &x, 8);
|
||||
__builtin_memcpy(b + n - 8, &x, 8);
|
||||
return p;
|
||||
default:
|
||||
unreachable;
|
||||
long Ai, Bi, Ci, Di;
|
||||
long Ao, Bo, Co, Do;
|
||||
const char *p, *e;
|
||||
t = 0;
|
||||
p = a;
|
||||
e = p + n;
|
||||
if (!IsTiny()) {
|
||||
if (X86_HAVE(POPCNT)) {
|
||||
while (p + sizeof(long) * 4 <= e) {
|
||||
__builtin_memcpy(&Ai, p + 000, sizeof(long));
|
||||
__builtin_memcpy(&Bi, p + 010, sizeof(long));
|
||||
__builtin_memcpy(&Ci, p + 020, sizeof(long));
|
||||
__builtin_memcpy(&Di, p + 030, sizeof(long));
|
||||
asm("popcnt\t%1,%0" : "=r"(Ao) : "r"(Ai) : "cc");
|
||||
asm("popcnt\t%1,%0" : "=r"(Bo) : "r"(Bi) : "cc");
|
||||
asm("popcnt\t%1,%0" : "=r"(Co) : "r"(Ci) : "cc");
|
||||
asm("popcnt\t%1,%0" : "=r"(Do) : "r"(Di) : "cc");
|
||||
t += Ao + Bo + Co + Do;
|
||||
p += sizeof(long) * 4;
|
||||
}
|
||||
while (p + sizeof(long) <= e) {
|
||||
__builtin_memcpy(&Ai, p, 8);
|
||||
asm("popcnt\t%1,%0" : "=r"(Ao) : "rm"(Ai) : "cc");
|
||||
p += sizeof(long);
|
||||
t += Ao;
|
||||
}
|
||||
} else {
|
||||
while (p + 8 <= e) {
|
||||
__builtin_memcpy(&x, p, 8);
|
||||
x = x - ((x >> 1) & 0x5555555555555555);
|
||||
x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333);
|
||||
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
|
||||
x = (x + (x >> 32)) & 0xffffffff;
|
||||
x = x + (x >> 16);
|
||||
x = (x + (x >> 8)) & 0x7f;
|
||||
t += x;
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (p < e) {
|
||||
b = *p++ & 255;
|
||||
b = b - ((b >> 1) & 0x55);
|
||||
b = ((b >> 2) & 0x33) + (b & 0x33);
|
||||
b = (b + (b >> 4)) & 15;
|
||||
t += b;
|
||||
}
|
||||
return t;
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
size_t _countbits(const void *, size_t);
|
||||
unsigned long popcnt(unsigned long) pureconst;
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
|
16
libc/bits/xadd.h
Normal file
16
libc/bits/xadd.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_XADD_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_XADD_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define _xadd(p, v) \
|
||||
({ \
|
||||
typeof(*(p)) Res; \
|
||||
autotype(Res) Val = (v); \
|
||||
asm volatile("xadd\t%0,%1" : "=r"(Res), "+m"(*(p)) : "0"(Val)); \
|
||||
Res + Val; \
|
||||
})
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_XADD_H_ */
|
|
@ -17,18 +17,21 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_chdir_nt(const char *path) {
|
||||
uint32_t n;
|
||||
int e, ms, len;
|
||||
char16_t path16[PATH_MAX];
|
||||
char16_t path16[PATH_MAX], var[4];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (path16[len - 1] != u'\\') {
|
||||
if (len + 1 + 1 > PATH_MAX) return enametoolong();
|
||||
if (len && path16[len - 1] != u'\\') {
|
||||
if (len + 2 > PATH_MAX) return enametoolong();
|
||||
path16[len + 0] = u'\\';
|
||||
path16[len + 1] = u'\0';
|
||||
}
|
||||
|
@ -38,7 +41,28 @@ textwindows int sys_chdir_nt(const char *path) {
|
|||
*/
|
||||
for (ms = 1;; ms *= 2) {
|
||||
if (SetCurrentDirectory(path16)) {
|
||||
return 0;
|
||||
/*
|
||||
* Now we need to set a magic environment variable.
|
||||
*/
|
||||
if ((n = GetCurrentDirectory(ARRAYLEN(path16), path16))) {
|
||||
if (n < ARRAYLEN(path16)) {
|
||||
if (!((path16[0] == '/' && path16[1] == '/') ||
|
||||
(path16[0] == '\\' && path16[1] == '\\'))) {
|
||||
var[0] = '=';
|
||||
var[1] = path16[0];
|
||||
var[2] = ':';
|
||||
var[3] = 0;
|
||||
if (!SetEnvironmentVariable(var, path16)) {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return enametoolong();
|
||||
}
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
} else {
|
||||
e = GetLastError();
|
||||
if (ms <= 512 &&
|
||||
|
|
|
@ -32,8 +32,6 @@
|
|||
* CHECK_NE(-1, chmod("/usr/bin/sudo", 04755)); // setuid bit
|
||||
* CHECK_NE(-1, chmod("/usr/bin/wall", 02755)); // setgid bit
|
||||
*
|
||||
* This works on Windows NT if you ignore the error ;-)
|
||||
*
|
||||
* @param pathname must exist
|
||||
* @param mode contains octal flags (base 8)
|
||||
* @errors ENOENT, ENOTDIR, ENOSYS
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
*/
|
||||
int close(int fd) {
|
||||
int rc;
|
||||
if (fd == -1) return 0;
|
||||
if (fd < 0) return einval();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = weaken(__zipos_close)(fd);
|
||||
|
@ -59,5 +61,6 @@ int close(int fd) {
|
|||
}
|
||||
}
|
||||
__releasefd(fd);
|
||||
SYSDEBUG("close(%d) -> %d", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static bool AccessCommand(char path[hasatleast PATH_MAX], const char *name,
|
||||
size_t namelen, size_t pathlen) {
|
||||
static noasan bool AccessCommand(char path[hasatleast PATH_MAX],
|
||||
const char *name, size_t namelen,
|
||||
size_t pathlen) {
|
||||
if (pathlen + 1 + namelen + 1 + 4 + 1 > PATH_MAX) return -1;
|
||||
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
|
||||
path[pathlen] = !IsWindows() ? '/'
|
||||
|
@ -40,8 +41,8 @@ static bool AccessCommand(char path[hasatleast PATH_MAX], const char *name,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
|
||||
size_t namelen) {
|
||||
static noasan bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
|
||||
size_t namelen) {
|
||||
size_t i;
|
||||
const char *p;
|
||||
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
|
||||
|
@ -70,7 +71,7 @@ static bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
|
|||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
||||
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
||||
char *p;
|
||||
size_t namelen;
|
||||
int rc, olderr;
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "libc/time/time.h"
|
||||
|
||||
static textwindows int sys_copyfile_nt(const char *src, const char *dst,
|
||||
int flags) {
|
||||
int flags) {
|
||||
int64_t fhsrc, fhdst;
|
||||
struct NtFileTime accessed, modified;
|
||||
char16_t src16[PATH_MAX], dst16[PATH_MAX];
|
||||
|
@ -99,6 +99,13 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
|
|||
|
||||
/**
|
||||
* Copies file.
|
||||
*
|
||||
* This implementation goes 2x faster than the `cp` command that comes
|
||||
* included with most systems since we use the newer copy_file_range()
|
||||
* system call rather than sendfile().
|
||||
*
|
||||
* @param flags may have COPYFILE_PRESERVE_TIMESTAMPS, COPYFILE_NOCLOBBER
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int copyfile(const char *src, const char *dst, int flags) {
|
||||
if (!IsWindows()) {
|
||||
|
|
|
@ -47,6 +47,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags) {
|
|||
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
|
||||
0, true, kNtDuplicateSameAccess)) {
|
||||
g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
|
||||
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
|
||||
g_fds.p[newfd].flags = flags;
|
||||
return newfd;
|
||||
} else {
|
||||
|
|
|
@ -35,7 +35,7 @@ int __ensurefds(int fd) {
|
|||
n2 = MAX(fd + 1, n1 + (n1 << 1));
|
||||
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
||||
memcpy(p2, p1, n1 * sizeof(*p1));
|
||||
memset(p2 + n1, 0, (n2 - n1) * sizeof(*p1));
|
||||
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
|
||||
if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1);
|
||||
if (cmpxchg(&g_fds.p, p1, p2)) {
|
||||
g_fds.n = n2;
|
||||
|
|
|
@ -37,7 +37,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
|||
uint32_t dwExitCode;
|
||||
struct NtStartupInfo startinfo;
|
||||
struct NtProcessInformation procinfo;
|
||||
memset(&startinfo, 0, sizeof(startinfo));
|
||||
bzero(&startinfo, sizeof(startinfo));
|
||||
startinfo.cb = sizeof(struct NtStartupInfo);
|
||||
startinfo.dwFlags = kNtStartfUsestdhandles;
|
||||
startinfo.hStdInput = g_fds.p[0].handle;
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -44,6 +46,19 @@ int execve(const char *program, char *const argv[], char *const envp[]) {
|
|||
!__asan_is_valid_strlist(envp))) {
|
||||
return efault();
|
||||
}
|
||||
if (DEBUGSYS) {
|
||||
__printf("SYS: execve(%s, {", program);
|
||||
for (i = 0; argv[i]; ++i) {
|
||||
if (i) __printf(", ");
|
||||
__printf("%s", argv[i]);
|
||||
}
|
||||
__printf("}, {");
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (i) __printf(", ");
|
||||
__printf("%s", envp[i]);
|
||||
}
|
||||
__printf("})\n");
|
||||
}
|
||||
for (i = 3; i < g_fds.n; ++i) {
|
||||
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {
|
||||
close(i);
|
||||
|
|
39
libc/calls/fchmodat-nt.c
Normal file
39
libc/calls/fchmodat-nt.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*-*- 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 2021 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/calls/internal.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/files.h"
|
||||
|
||||
textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
|
||||
int flags) {
|
||||
uint32_t attr;
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if ((attr = GetFileAttributes(path16)) != -1) {
|
||||
if (mode & 0200) {
|
||||
attr &= ~kNtFileAttributeReadonly;
|
||||
} else {
|
||||
attr |= kNtFileAttributeReadonly;
|
||||
}
|
||||
if (SetFileAttributes(path16, attr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return __winerr();
|
||||
}
|
|
@ -31,8 +31,6 @@
|
|||
* CHECK_NE(-1, fchmodat(AT_FDCWD, "o/default/program.com", 0755));
|
||||
* CHECK_NE(-1, fchmodat(AT_FDCWD, "privatefolder/", 0700));
|
||||
*
|
||||
* This works on Windows NT if you ignore the error ;-)
|
||||
*
|
||||
* @param path must exist
|
||||
* @param mode contains octal flags (base 8)
|
||||
* @param flags can have `AT_SYMLINK_NOFOLLOW`
|
||||
|
|
|
@ -29,7 +29,7 @@ textwindows int sys_flock_nt(int fd, int op) {
|
|||
struct NtOverlapped ov;
|
||||
struct NtByHandleFileInformation info;
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
bzero(&ov, sizeof(ov));
|
||||
if (GetFileInformationByHandle(g_fds.p[fd].handle, &info) &&
|
||||
((!(op & LOCK_UN) &&
|
||||
LockFileEx(g_fds.p[fd].handle, op, 0, info.nFileSizeLow,
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
int sys_fstat_metal(int fd, struct stat *st) {
|
||||
if (fd < 0) return einval();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
|
||||
memset(st, 0, sizeof(*st));
|
||||
bzero(st, sizeof(*st));
|
||||
st->st_dev = g_fds.p[fd].handle;
|
||||
st->st_rdev = g_fds.p[fd].handle;
|
||||
st->st_nlink = 1;
|
||||
|
|
|
@ -76,7 +76,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
|
|||
struct NtByHandleFileInformation wst;
|
||||
if (!st) return efault();
|
||||
if ((filetype = GetFileType(handle))) {
|
||||
memset(st, 0, sizeof(*st));
|
||||
bzero(st, sizeof(*st));
|
||||
switch (filetype) {
|
||||
case kNtFileTypeChar:
|
||||
st->st_mode = S_IFCHR | 0644;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -41,6 +42,7 @@ int32_t sys_fstat(int32_t fd, struct stat *st) {
|
|||
__stat2cosmo(st, &ms);
|
||||
return 0;
|
||||
} else {
|
||||
SYSDEBUG("sys_fstat(%d) failed w/ %m", fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,9 +32,7 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
|
|||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(
|
||||
path16, kNtFileReadAttributes,
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, NULL,
|
||||
kNtOpenExisting,
|
||||
path16, kNtFileReadAttributes, 0, 0, kNtOpenExisting,
|
||||
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
|
||||
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
|
||||
: 0),
|
||||
|
|
|
@ -34,7 +34,7 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
|
|||
struct NtFileTime UserFileTime;
|
||||
if (!usage) return efault();
|
||||
if (who == 99) return enosys(); /* @see libc/sysv/consts.sh */
|
||||
memset(usage, 0, sizeof(*usage));
|
||||
bzero(usage, sizeof(*usage));
|
||||
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
|
||||
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
|
||||
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
|
||||
|
|
|
@ -29,6 +29,6 @@ int sys_gettimeofday_nt(struct timeval *tv, struct timezone *tz) {
|
|||
struct NtFileTime ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
if (tv) *tv = FileTimeToTimeVal(ft);
|
||||
if (tz) memset(tz, 0, sizeof(*tz));
|
||||
if (tz) bzero(tz, sizeof(*tz));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -261,6 +261,7 @@ int sys_execve_nt(const char *, char *const[], char *const[]) hidden;
|
|||
int sys_faccessat_nt(int, const char *, int, uint32_t) hidden;
|
||||
int sys_fadvise_nt(int, u64, u64, int) hidden;
|
||||
int sys_fchdir_nt(int) hidden;
|
||||
int sys_fchmodat_nt(int, const char *, uint32_t, int) hidden;
|
||||
int sys_fcntl_nt(int, int, uintptr_t) hidden;
|
||||
int sys_fdatasync_nt(int) hidden;
|
||||
int sys_flock_nt(int, int) hidden;
|
||||
|
|
|
@ -76,7 +76,7 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
|
|||
fam = p[IsBsd() ? 17 : 16] & 255;
|
||||
if (fam != AF_INET) continue;
|
||||
ip = READ32BE(p + 20);
|
||||
memset(req, 0, sizeof(*req));
|
||||
bzero(req, sizeof(*req));
|
||||
memcpy(req->ifr_name, p, 16);
|
||||
memcpy(&req->ifr_addr, p + 16, 16);
|
||||
req->ifr_addr.sa_family = fam;
|
||||
|
|
|
@ -34,7 +34,7 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) {
|
|||
inok = GetConsoleMode((in = g_fds.p[0].handle), &inmode);
|
||||
outok = GetConsoleMode((out = g_fds.p[1].handle), &outmode);
|
||||
if (inok | outok) {
|
||||
memset(tio, 0, sizeof(*tio));
|
||||
bzero(tio, sizeof(*tio));
|
||||
if (inok) {
|
||||
if (inmode & kNtEnableLineInput) tio->c_lflag |= ICANON;
|
||||
if (inmode & kNtEnableEchoInput) tio->c_lflag |= ECHO;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
int ioctl_tcgets_nt(int, struct termios *) hidden;
|
||||
|
||||
static int ioctl_tcgets_metal(int fd, struct termios *tio) {
|
||||
memset(tio, 0, sizeof(*tio));
|
||||
bzero(tio, sizeof(*tio));
|
||||
tio->c_iflag = TTYDEF_IFLAG;
|
||||
tio->c_oflag = TTYDEF_OFLAG;
|
||||
tio->c_lflag = TTYDEF_LFLAG;
|
||||
|
|
|
@ -38,7 +38,7 @@ textwindows int ioctl_tiocgwinsz_nt(int fd, struct winsize *ws) {
|
|||
for (i = 0; i < ARRAYLEN(fds); ++i) {
|
||||
if (__isfdkind(fds[i], kFdFile) || __isfdkind(fds[i], kFdConsole)) {
|
||||
if (GetConsoleMode(g_fds.p[fds[i]].handle, &mode)) {
|
||||
memset(&sbinfo, 0, sizeof(sbinfo));
|
||||
bzero(&sbinfo, sizeof(sbinfo));
|
||||
sbinfo.cbSize = sizeof(sbinfo);
|
||||
if (GetConsoleScreenBufferInfoEx(g_fds.p[fds[i]].handle, &sbinfo)) {
|
||||
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;
|
||||
|
|
|
@ -31,7 +31,9 @@ bool32 isatty(int fd) {
|
|||
bool32 res;
|
||||
struct winsize ws;
|
||||
if (fd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
return false;
|
||||
} else if (IsMetal()) {
|
||||
return false;
|
||||
} else if (!IsWindows()) {
|
||||
err = errno;
|
||||
|
|
|
@ -19,9 +19,19 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
bool g_isrunningundermake;
|
||||
|
||||
/**
|
||||
* Returns true if current process was spawned by GNU Make.
|
||||
*/
|
||||
bool IsRunningUnderMake(void) {
|
||||
return !!getenv("MAKEFLAGS");
|
||||
return g_isrunningundermake;
|
||||
}
|
||||
|
||||
textstartup void g_isrunningundermake_init(void) {
|
||||
g_isrunningundermake = !!getenv("MAKEFLAGS");
|
||||
}
|
||||
|
||||
const void *const g_isrunningundermake_ctor[] initarray = {
|
||||
g_isrunningundermake_init,
|
||||
};
|
||||
|
|
|
@ -23,6 +23,22 @@
|
|||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define APPEND(c) \
|
||||
do { \
|
||||
cmdline[k++] = c; \
|
||||
if (k == ARG_MAX) return e2big(); \
|
||||
} while (0)
|
||||
|
||||
static noasan bool NeedsQuotes(const char *s) {
|
||||
if (!*s) return true;
|
||||
do {
|
||||
if (*s == ' ' || *s == '\t') {
|
||||
return true;
|
||||
}
|
||||
} while (*s++);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts System V argv to Windows-style command line.
|
||||
*
|
||||
|
@ -34,7 +50,6 @@
|
|||
* @param prog is used as argv[0]
|
||||
* @param argv is an a NULL-terminated array of UTF-8 strings
|
||||
* @return freshly allocated lpCommandLine or NULL w/ errno
|
||||
* @kudos Daniel Colascione for teaching how to quote
|
||||
* @see libc/runtime/dosargv.c
|
||||
*/
|
||||
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||
|
@ -43,36 +58,19 @@ textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
|||
uint64_t w;
|
||||
wint_t x, y;
|
||||
int slashes, n;
|
||||
size_t i, j, k;
|
||||
bool needsquote;
|
||||
char16_t cbuf[2];
|
||||
size_t i, j, k, s;
|
||||
for (arg = prog, k = i = 0; arg; arg = argv[++i]) {
|
||||
if (i) {
|
||||
cmdline[k++] = u' ';
|
||||
if (k == ARG_MAX) return e2big();
|
||||
}
|
||||
needsquote = !arg[0] || arg[strcspn(arg, " \t\n\v\"")];
|
||||
if (needsquote) {
|
||||
cmdline[k++] = u'"';
|
||||
if (k == ARG_MAX) return e2big();
|
||||
}
|
||||
for (j = 0;;) {
|
||||
if (needsquote) {
|
||||
slashes = 0;
|
||||
while (arg[j] && arg[j] == '\\') slashes++, j++;
|
||||
slashes <<= 1;
|
||||
if (arg[j] == '"') slashes++;
|
||||
while (slashes--) {
|
||||
cmdline[k++] = u'\\';
|
||||
if (k == ARG_MAX) return e2big();
|
||||
}
|
||||
}
|
||||
x = arg[j++] & 0xff;
|
||||
if (i) APPEND(u' ');
|
||||
if ((needsquote = NeedsQuotes(arg))) APPEND(u'"');
|
||||
for (slashes = j = 0;;) {
|
||||
x = arg[j++] & 255;
|
||||
if (x >= 0300) {
|
||||
n = ThomPikeLen(x);
|
||||
x = ThomPikeByte(x);
|
||||
while (--n) {
|
||||
if ((y = arg[j++] & 0xff)) {
|
||||
if ((y = arg[j++] & 255)) {
|
||||
x = ThomPikeMerge(x, y);
|
||||
} else {
|
||||
x = 0;
|
||||
|
@ -81,16 +79,34 @@ textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
|||
}
|
||||
}
|
||||
if (!x) break;
|
||||
if (!i && x == '/') x = '\\';
|
||||
w = EncodeUtf16(x);
|
||||
do {
|
||||
cmdline[k++] = w;
|
||||
if (k == ARG_MAX) return e2big();
|
||||
} while ((w >>= 16));
|
||||
if (!i && x == '/') {
|
||||
x = '\\';
|
||||
}
|
||||
if (x == '\\') {
|
||||
++slashes;
|
||||
} else if (x == '"') {
|
||||
for (s = 0; s < slashes * 2; ++s) {
|
||||
APPEND(u'\\');
|
||||
}
|
||||
slashes = 0;
|
||||
APPEND(u'\\');
|
||||
APPEND(u'"');
|
||||
} else {
|
||||
for (s = 0; s < slashes; ++s) {
|
||||
APPEND(u'\\');
|
||||
}
|
||||
slashes = 0;
|
||||
w = EncodeUtf16(x);
|
||||
do {
|
||||
APPEND(w);
|
||||
} while ((w >>= 16));
|
||||
}
|
||||
}
|
||||
for (s = 0; s < (slashes << needsquote); ++s) {
|
||||
APPEND(u'\\');
|
||||
}
|
||||
if (needsquote) {
|
||||
cmdline[k++] = u'"';
|
||||
if (k == ARG_MAX) return e2big();
|
||||
APPEND(u'"');
|
||||
}
|
||||
}
|
||||
cmdline[k] = u'\0';
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_nanosleep_nt(const struct timespec *req, struct timespec *rem) {
|
||||
textwindows int sys_nanosleep_nt(const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int64_t millis, hectonanos, relasleep;
|
||||
if (rem) memcpy(rem, req, sizeof(*rem));
|
||||
hectonanos = req->tv_sec * 10000000ull + div100int64(req->tv_nsec);
|
||||
|
@ -38,6 +39,6 @@ textwindows int sys_nanosleep_nt(const struct timespec *req, struct timespec *re
|
|||
return eintr();
|
||||
}
|
||||
}
|
||||
if (rem) memset(rem, 0, sizeof(*rem));
|
||||
if (rem) bzero(rem, sizeof(*rem));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
|
|||
s = (void *)buffer;
|
||||
secsize = sizeof(buffer);
|
||||
privsize = sizeof(privileges);
|
||||
memset(&privileges, 0, sizeof(privileges));
|
||||
bzero(&privileges, sizeof(privileges));
|
||||
mapping.GenericRead = kNtFileGenericRead;
|
||||
mapping.GenericWrite = kNtFileGenericWrite;
|
||||
mapping.GenericExecute = kNtFileGenericExecute;
|
||||
|
|
|
@ -33,6 +33,14 @@ textwindows void ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
|
|||
ctx->uc_mcontext.rbp = cr->Rbp;
|
||||
ctx->uc_mcontext.rsp = cr->Rsp;
|
||||
ctx->uc_mcontext.rip = cr->Rip;
|
||||
ctx->uc_mcontext.r8 = cr->R8;
|
||||
ctx->uc_mcontext.r9 = cr->R9;
|
||||
ctx->uc_mcontext.r10 = cr->R10;
|
||||
ctx->uc_mcontext.r11 = cr->R11;
|
||||
ctx->uc_mcontext.r12 = cr->R12;
|
||||
ctx->uc_mcontext.r13 = cr->R13;
|
||||
ctx->uc_mcontext.r14 = cr->R14;
|
||||
ctx->uc_mcontext.r15 = cr->R15;
|
||||
ctx->uc_mcontext.cs = cr->SegCs;
|
||||
ctx->uc_mcontext.gs = cr->SegGs;
|
||||
ctx->uc_mcontext.fs = cr->SegFs;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/ntspawn.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
|
@ -69,8 +70,10 @@ textwindows int ntspawn(
|
|||
int64_t handle;
|
||||
size_t blocksize;
|
||||
struct SpawnBlock *block;
|
||||
char16_t prog16[PATH_MAX];
|
||||
rc = -1;
|
||||
block = NULL;
|
||||
if (__mkntpath(prog, prog16) == -1) return -1;
|
||||
blocksize = ROUNDUP(sizeof(*block), FRAMESIZE);
|
||||
if ((handle = CreateFileMappingNuma(
|
||||
-1,
|
||||
|
@ -83,7 +86,7 @@ textwindows int ntspawn(
|
|||
blocksize, NULL, kNtNumaNoPreferredNode))) {
|
||||
if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
|
||||
mkntenvblock(block->envvars, envp, extravar) != -1) {
|
||||
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
|
||||
if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
|
||||
opt_lpThreadAttributes, bInheritHandles,
|
||||
dwCreationFlags | kNtCreateUnicodeEnvironment,
|
||||
block->envvars, opt_lpCurrentDirectory, lpStartupInfo,
|
||||
|
@ -92,6 +95,7 @@ textwindows int ntspawn(
|
|||
} else {
|
||||
__winerr();
|
||||
}
|
||||
SYSDEBUG("CreateProcess(`%S`, `%S`) -> %d", prog16, block->cmdline, rc);
|
||||
}
|
||||
} else {
|
||||
__winerr();
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
textwindows struct NtOverlapped *offset2overlap(int64_t opt_offset,
|
||||
struct NtOverlapped *mem) {
|
||||
if (opt_offset == -1) return NULL;
|
||||
memset(mem, 0, sizeof(struct NtOverlapped));
|
||||
bzero(mem, sizeof(struct NtOverlapped));
|
||||
mem->Pointer = (void *)(uintptr_t)opt_offset;
|
||||
return mem;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
|
|||
case (uintptr_t)SIG_IGN:
|
||||
return true;
|
||||
default:
|
||||
memset(&info, 0, sizeof(info));
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
((sigaction_f)(_base + rva))(sig, &info, NULL);
|
||||
__interrupted = true;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
|
@ -32,7 +33,7 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
|
|||
* flag. Other times, it return -530 which makes no sense.
|
||||
*/
|
||||
if (!IsLinux() || !(flags & O_CLOEXEC) || modernize) {
|
||||
return __sys_openat(dirfd, file, flags, mode);
|
||||
d = __sys_openat(dirfd, file, flags, mode);
|
||||
} else if (once) {
|
||||
if ((d = __sys_openat(dirfd, file, flags & ~O_CLOEXEC, mode)) != -1) {
|
||||
e = errno;
|
||||
|
@ -54,8 +55,13 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
|
|||
once = true;
|
||||
} else if (errno > 255) {
|
||||
once = true;
|
||||
return sys_openat(dirfd, file, flags, mode);
|
||||
d = sys_openat(dirfd, file, flags, mode);
|
||||
}
|
||||
}
|
||||
if (d != -1) {
|
||||
SYSDEBUG("sys_openat(0x%x, %s, %d, %d) -> %d", dirfd, file, flags, mode, d);
|
||||
} else {
|
||||
SYSDEBUG("sys_openat(0x%x, %s, %d, %d) -> %m", dirfd, file, flags, mode);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ ssize_t readansi(int fd, char *p, size_t n) {
|
|||
case kCsi1:
|
||||
if (0x20 <= c && c <= 0x2f) {
|
||||
t = kCsi2;
|
||||
} else if (c == '[' && i == 3) {
|
||||
} else if (c == '[' && (i == 3 || (i == 4 && p[1] == '\e'))) {
|
||||
/* linux function keys */
|
||||
} else if (0x40 <= c && c <= 0x7e) {
|
||||
t = kDone;
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
#include "libc/str/str.h"
|
||||
|
||||
static textwindows noinline int sys_sched_setaffinity_nt(int pid,
|
||||
uint64_t bitsetsize,
|
||||
const void *bitset) {
|
||||
uint64_t bitsetsize,
|
||||
const void *bitset) {
|
||||
int rc;
|
||||
uintptr_t mask;
|
||||
int64_t handle;
|
||||
|
|
|
@ -49,12 +49,12 @@
|
|||
autotype((S2).B) b = (typeof((S2).B))(S1).B; \
|
||||
autotype((S2).C) c = (typeof((S2).C))(S1).C; \
|
||||
typeof((S2).D) d; \
|
||||
memset(&d, 0, sizeof(d)); \
|
||||
bzero(&d, sizeof(d)); \
|
||||
memcpy(&d, &((S1).D), MIN(sizeof(d), sizeof((S1).D))); \
|
||||
(S2).A = a; \
|
||||
(S2).B = b; \
|
||||
(S2).C = c; \
|
||||
memset(&((S2).D), 0, sizeof((S2).D)); \
|
||||
bzero(&((S2).D), sizeof((S2).D)); \
|
||||
memcpy(&((S2).D), &d, MIN(sizeof(d), sizeof((S2).D))); \
|
||||
} while (0);
|
||||
#endif
|
||||
|
@ -217,7 +217,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
}
|
||||
} else {
|
||||
if (oldact) {
|
||||
memset(oldact, 0, sizeof(*oldact));
|
||||
bzero(oldact, sizeof(*oldact));
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,6 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigemptyset(sigset_t *set) {
|
||||
memset(set->__bits, 0, sizeof(set->__bits));
|
||||
bzero(set->__bits, sizeof(set->__bits));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *si,
|
|||
ucontext_t uc;
|
||||
rva = __sighandrvas[sig & (NSIG - 1)];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
memset(&uc, 0, sizeof(uc));
|
||||
bzero(&uc, sizeof(uc));
|
||||
if (ctx) {
|
||||
uc.uc_mcontext.fpregs = &uc.__fpustate;
|
||||
uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
|
||||
|
@ -155,6 +155,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *si,
|
|||
uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs;
|
||||
uc.uc_mcontext.err = ctx->uc_mcontext.mc_err;
|
||||
uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno;
|
||||
memcpy(&uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512);
|
||||
}
|
||||
((sigaction_f)(_base + rva))(sig, (void *)si, &uc);
|
||||
if (ctx) {
|
||||
|
@ -186,6 +187,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *si,
|
|||
ctx->uc_mcontext.mc_err = uc.uc_mcontext.err;
|
||||
ctx->uc_mcontext.mc_rip = uc.uc_mcontext.rip;
|
||||
ctx->uc_mcontext.mc_rsp = uc.uc_mcontext.rsp;
|
||||
memcpy(&ctx->uc_mcontext.mc_fpstate, &uc.__fpustate, 512);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -132,8 +132,8 @@ void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
|
|||
struct siginfo si2;
|
||||
rva = __sighandrvas[sig & (NSIG - 1)];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
memset(&uc, 0, sizeof(uc));
|
||||
memset(&si2, 0, sizeof(si2));
|
||||
bzero(&uc, sizeof(uc));
|
||||
bzero(&si2, sizeof(si2));
|
||||
if (si) {
|
||||
si2.si_signo = si->_signo;
|
||||
si2.si_code = si->_code;
|
||||
|
|
|
@ -97,8 +97,8 @@ void __sigenter_openbsd(int sig, struct siginfo_openbsd *si,
|
|||
struct siginfo si2;
|
||||
rva = __sighandrvas[sig & (NSIG - 1)];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
memset(&uc, 0, sizeof(uc));
|
||||
memset(&si2, 0, sizeof(si2));
|
||||
bzero(&uc, sizeof(uc));
|
||||
bzero(&si2, sizeof(si2));
|
||||
if (si) {
|
||||
si2.si_signo = si->si_signo;
|
||||
si2.si_code = si->si_code;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*/
|
||||
int sigignore(int sig) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sa_handler = SIG_IGN;
|
||||
return (sigaction)(sig, &sa, 0);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ int sigqueue(int pid, int sig, const union sigval value) {
|
|||
if (IsFreebsd()) {
|
||||
return sys_sigqueue(pid, sig, value);
|
||||
} else {
|
||||
memset(&info, 0, sizeof(info));
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
info.si_code = SI_QUEUE;
|
||||
info.si_pid = getpid();
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_SYSDEBUG_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_SYSDEBUG_INTERNAL_H_
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
|
||||
#if 0
|
||||
#define SYSDEBUG(FMT, ...) (dprintf)(2, FMT "\n", ##__VA_ARGS__)
|
||||
#ifndef DEBUGSYS
|
||||
#define DEBUGSYS 0
|
||||
#endif
|
||||
|
||||
#if DEBUGSYS
|
||||
#define SYSDEBUG(FMT, ...) __printf("SYS: " FMT "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define SYSDEBUG(FMT, ...) (void)0
|
||||
#endif
|
||||
|
|
|
@ -41,7 +41,7 @@ int sysinfo(struct sysinfo *info) {
|
|||
return efault();
|
||||
}
|
||||
}
|
||||
memset(info, 0, sizeof(*info));
|
||||
bzero(info, sizeof(*info));
|
||||
if (!IsWindows()) {
|
||||
rc = sys_sysinfo(info);
|
||||
} else {
|
||||
|
|
|
@ -29,7 +29,7 @@ int uname(struct utsname *lool) {
|
|||
char *out;
|
||||
size_t i, j, len;
|
||||
char tmp[sizeof(struct utsname)];
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
bzero(tmp, sizeof(tmp));
|
||||
if (sys_uname(tmp) != -1) {
|
||||
out = (char *)lool;
|
||||
i = 0;
|
||||
|
@ -45,7 +45,7 @@ int uname(struct utsname *lool) {
|
|||
}
|
||||
return 0;
|
||||
} else {
|
||||
memset(lool, 0, sizeof(struct utsname));
|
||||
bzero(lool, sizeof(struct utsname));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,11 @@
|
|||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Deletes file.
|
||||
* Removes file.
|
||||
*
|
||||
* Please note the deletion process has different interesting properties
|
||||
* on each platform. For example, on System V, if open descriptors exist
|
||||
* then only the name of the file is removed and it's actually deleted
|
||||
* later on when appropriate.
|
||||
* This may be used to delete files but it can't be used to delete
|
||||
* directories. The exception are symlinks, which this will delete
|
||||
* however not the linked directory.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
|
|
|
@ -18,17 +18,29 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/io.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/win32fileattributedata.h"
|
||||
#include "libc/nt/struct/win32finddata.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
static textwindows int sys_unlink_nt(const char16_t *path) {
|
||||
if (DeleteFile(path)) {
|
||||
return 0;
|
||||
static textwindows bool IsDirectorySymlink(const char16_t *path) {
|
||||
int64_t h;
|
||||
struct NtWin32FindData data;
|
||||
struct NtWin32FileAttributeData info;
|
||||
if (GetFileAttributesEx(path, 0, &info) &&
|
||||
((info.dwFileAttributes & kNtFileAttributeDirectory) &&
|
||||
(info.dwFileAttributes & kNtFileAttributeReparsePoint)) &&
|
||||
(h = FindFirstFile(path, &data)) != -1) {
|
||||
FindClose(h);
|
||||
return data.dwReserved0 == kNtIoReparseTagSymlink ||
|
||||
data.dwReserved0 == kNtIoReparseTagMountPoint;
|
||||
} else {
|
||||
return __winerr();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,6 +66,11 @@ static textwindows int sys_rmdir_nt(const char16_t *path) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static textwindows int sys_unlink_nt(const char16_t *path) {
|
||||
if (IsDirectorySymlink(path)) return sys_rmdir_nt(path);
|
||||
return DeleteFile(path) ? 0 : __winerr();
|
||||
}
|
||||
|
||||
textwindows int sys_unlinkat_nt(int dirfd, const char *path, int flags) {
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
|
|
|
@ -84,7 +84,7 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
|
|||
*opt_out_wstatus = (dwExitCode & 0xff) << 8;
|
||||
}
|
||||
if (opt_out_rusage) {
|
||||
memset(opt_out_rusage, 0, sizeof(*opt_out_rusage));
|
||||
bzero(opt_out_rusage, sizeof(*opt_out_rusage));
|
||||
if (GetProcessTimes(g_fds.p[pids[i]].handle, &createfiletime,
|
||||
&exitfiletime, &kernelfiletime, &userfiletime)) {
|
||||
opt_out_rusage->ru_utime =
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/calls/wait4.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
|
@ -37,6 +38,7 @@
|
|||
*/
|
||||
int wait4(int pid, int *opt_out_wstatus, int options,
|
||||
struct rusage *opt_out_rusage) {
|
||||
int rc, ws;
|
||||
if (IsAsan() &&
|
||||
((opt_out_wstatus &&
|
||||
!__asan_is_valid(opt_out_wstatus, sizeof(*opt_out_wstatus))) ||
|
||||
|
@ -44,9 +46,13 @@ int wait4(int pid, int *opt_out_wstatus, int options,
|
|||
!__asan_is_valid(opt_out_rusage, sizeof(*opt_out_rusage))))) {
|
||||
return efault();
|
||||
}
|
||||
ws = 0;
|
||||
if (!IsWindows()) {
|
||||
return sys_wait4(pid, opt_out_wstatus, options, opt_out_rusage);
|
||||
rc = sys_wait4(pid, &ws, options, opt_out_rusage);
|
||||
} else {
|
||||
return sys_wait4_nt(pid, opt_out_wstatus, options, opt_out_rusage);
|
||||
rc = sys_wait4_nt(pid, &ws, options, opt_out_rusage);
|
||||
}
|
||||
SYSDEBUG("waitpid(%d, [0x%x], %d) -> [%d]", pid, ws, options, rc);
|
||||
if (opt_out_wstatus) *opt_out_wstatus = ws;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ void __winalarm(void *lpArgToCompletionRoutine, uint32_t dwTimerLowValue,
|
|||
uint32_t dwTimerHighValue) {
|
||||
int rva;
|
||||
siginfo_t info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = SIGALRM;
|
||||
rva = __sighandrvas[SIGALRM];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
|
|
|
@ -70,7 +70,7 @@ textwindows unsigned __wincrash(struct NtExceptionPointers *ep) {
|
|||
default:
|
||||
return kNtExceptionContinueSearch;
|
||||
}
|
||||
memset(&g, 0, sizeof(g));
|
||||
bzero(&g, sizeof(g));
|
||||
rva = __sighandrvas[sig];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
ntcontext2linux(&g.ctx, ep->ContextRecord);
|
||||
|
|
|
@ -61,7 +61,7 @@ int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
|
|||
if (addrsize < kMinSockaddr4Size) return einval();
|
||||
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
|
||||
if (!resolvconf->nameservers.i) return 0;
|
||||
memset(&h, 0, sizeof(h));
|
||||
bzero(&h, sizeof(h));
|
||||
rc = ebadmsg();
|
||||
h.id = rand64();
|
||||
h.bf1 = 1; /* recursion desired */
|
||||
|
@ -69,7 +69,7 @@ int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
|
|||
q.qname = name;
|
||||
q.qtype = DNS_TYPE_A;
|
||||
q.qclass = DNS_CLASS_IN;
|
||||
memset(msg, 0, sizeof(msg));
|
||||
bzero(msg, sizeof(msg));
|
||||
SerializeDnsHeader(msg, &h);
|
||||
if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;
|
||||
|
|
|
@ -63,7 +63,7 @@ int ResolveDnsReverse(const struct ResolvConf *resolvconf, int af,
|
|||
uint16_t rtype, rclass, rdlength;
|
||||
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
|
||||
if (!resolvconf->nameservers.i) return 0;
|
||||
memset(&h, 0, sizeof(h));
|
||||
bzero(&h, sizeof(h));
|
||||
rc = ebadmsg();
|
||||
h.id = rand64();
|
||||
h.bf1 = 1; /* recursion desired */
|
||||
|
@ -71,7 +71,7 @@ int ResolveDnsReverse(const struct ResolvConf *resolvconf, int af,
|
|||
q.qname = name;
|
||||
q.qtype = DNS_TYPE_PTR;
|
||||
q.qclass = DNS_CLASS_IN;
|
||||
memset(msg, 0, sizeof(msg));
|
||||
bzero(msg, sizeof(msg));
|
||||
SerializeDnsHeader(msg, &h);
|
||||
if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;
|
||||
|
|
|
@ -13,6 +13,7 @@ COSMOPOLITAN_C_START_
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
char *GetElfStringTable(const Elf64_Ehdr *, size_t);
|
||||
char *GetElfStrs(const Elf64_Ehdr *, size_t, size_t *);
|
||||
Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *, size_t, Elf64_Xword *);
|
||||
bool IsElf64Binary(const Elf64_Ehdr *, size_t);
|
||||
void CheckElfAddress(const Elf64_Ehdr *, size_t, intptr_t, size_t);
|
||||
|
|
39
libc/elf/getelfstrs.c
Normal file
39
libc/elf/getelfstrs.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
char *GetElfStrs(const Elf64_Ehdr *elf, size_t mapsize, size_t *out_size) {
|
||||
char *name;
|
||||
Elf64_Half i;
|
||||
Elf64_Shdr *shdr;
|
||||
for (i = 0; i < elf->e_shnum; ++i) {
|
||||
shdr = GetElfSectionHeaderAddress(elf, mapsize, i);
|
||||
if (shdr->sh_type == SHT_STRTAB) {
|
||||
name = GetElfSectionName(elf, mapsize,
|
||||
GetElfSectionHeaderAddress(elf, mapsize, i));
|
||||
if (name && !strcmp(name, ".strtab")) {
|
||||
if (out_size) *out_size = shdr->sh_size;
|
||||
return GetElfSectionAddress(elf, mapsize, shdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -24,6 +24,16 @@
|
|||
/**
|
||||
* Decodes decimal integer from ASCII string.
|
||||
*
|
||||
* atoi 10⁸ 22𝑐 7𝑛𝑠
|
||||
* strtol 10⁸ 37𝑐 12𝑛𝑠
|
||||
* strtoul 10⁸ 35𝑐 11𝑛𝑠
|
||||
* wcstol 10⁸ 30𝑐 10𝑛𝑠
|
||||
* wcstoul 10⁸ 30𝑐 10𝑛𝑠
|
||||
* strtoimax 10⁸ 80𝑐 26𝑛𝑠
|
||||
* strtoumax 10⁸ 78𝑐 25𝑛𝑠
|
||||
* wcstoimax 10⁸ 77𝑐 25𝑛𝑠
|
||||
* wcstoumax 10⁸ 76𝑐 25𝑛𝑠
|
||||
*
|
||||
* @param s is a non-null nul-terminated string
|
||||
* @return the decoded signed saturated integer
|
||||
*/
|
||||
|
|
|
@ -69,6 +69,7 @@ char *dirname(char *);
|
|||
char *basename(const char *) nosideeffect;
|
||||
char *basename_n(const char *, size_t) nosideeffect;
|
||||
bool isabspath(const char *) paramsnonnull() nosideeffect;
|
||||
char *stripext(char *);
|
||||
char *stripexts(char *);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
|
|
|
@ -391,7 +391,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
s = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
|
||||
if (decpt == 9999) {
|
||||
Format9999:
|
||||
p = q = memset(special, 0, sizeof(special));
|
||||
bzero(special, sizeof(special));
|
||||
p = q = special;
|
||||
if (sgn) {
|
||||
*q++ = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
|
@ -423,12 +424,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) PUT(sign);
|
||||
sign = 0;
|
||||
do
|
||||
PUT('0');
|
||||
do PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do
|
||||
PUT(' ');
|
||||
do PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
|
@ -530,12 +529,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) PUT(sign);
|
||||
sign = 0;
|
||||
do
|
||||
PUT('0');
|
||||
do PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do
|
||||
PUT(' ');
|
||||
do PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
|
@ -682,12 +679,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
PUT(sign);
|
||||
sign = 0;
|
||||
}
|
||||
do
|
||||
PUT('0');
|
||||
do PUT('0');
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do
|
||||
PUT(' ');
|
||||
do PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ $(LIBC_FMT_A_OBJS): \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-fno-jump-tables
|
||||
|
||||
o/$(MODE)/libc/fmt/formatint64.o \
|
||||
o/$(MODE)/libc/fmt/formatint64thousands.o \
|
||||
o/$(MODE)/libc/fmt/dosdatetimetounix.o \
|
||||
o/$(MODE)/libc/fmt/itoa64radix10.greg.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
|
|
55
libc/fmt/formatint64.c
Normal file
55
libc/fmt/formatint64.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*-*- 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 2021 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/fmt/itoa.h"
|
||||
|
||||
/**
|
||||
* Converts unsigned 64-bit integer to string.
|
||||
*
|
||||
* @param p needs at least 21 bytes
|
||||
* @return pointer to nul byte
|
||||
*/
|
||||
noinline char *FormatUint64(char p[static 21], uint64_t x) {
|
||||
char t;
|
||||
size_t i, a, b;
|
||||
i = 0;
|
||||
do {
|
||||
p[i++] = x % 10 + '0';
|
||||
x = x / 10;
|
||||
} while (x > 0);
|
||||
p[i] = '\0';
|
||||
if (i) {
|
||||
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
||||
t = p[a];
|
||||
p[a] = p[b];
|
||||
p[b] = t;
|
||||
}
|
||||
}
|
||||
return p + i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts signed 64-bit integer to string.
|
||||
*
|
||||
* @param p needs at least 21 bytes
|
||||
* @return pointer to nul byte
|
||||
*/
|
||||
char *FormatInt64(char p[static 21], int64_t x) {
|
||||
if (x < 0) *p++ = '-', x = -(uint64_t)x;
|
||||
return FormatUint64(p, x);
|
||||
}
|
53
libc/fmt/formatint64thousands.c
Normal file
53
libc/fmt/formatint64thousands.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*-*- 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 2021 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/fmt/itoa.h"
|
||||
|
||||
/**
|
||||
* Converts unsigned 64-bit integer to string w/ commas.
|
||||
*
|
||||
* @param p needs at least 21 bytes
|
||||
* @return pointer to nul byte
|
||||
*/
|
||||
noinline char *FormatUint64Thousands(char p[static 27], uint64_t x) {
|
||||
size_t i;
|
||||
char m[26];
|
||||
i = 0;
|
||||
do {
|
||||
m[i++] = x % 10 + '0';
|
||||
x = x / 10;
|
||||
} while (x);
|
||||
for (;;) {
|
||||
*p++ = m[--i];
|
||||
if (!i) break;
|
||||
if (!(i % 3)) *p++ = ',';
|
||||
}
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts 64-bit integer to string w/ commas.
|
||||
*
|
||||
* @param p needs at least 21 bytes
|
||||
* @return pointer to nul byte
|
||||
*/
|
||||
char *FormatInt64Thousands(char p[static 27], int64_t x) {
|
||||
if (x < 0) *p++ = '-', x = -(uint64_t)x;
|
||||
return FormatUint64Thousands(p, x);
|
||||
}
|
|
@ -16,6 +16,10 @@ COSMOPOLITAN_C_START_
|
|||
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
|
||||
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */
|
||||
|
||||
char *FormatInt64(char[hasatleast 21], int64_t);
|
||||
char *FormatUint64(char[hasatleast 21], uint64_t);
|
||||
char *FormatInt64Thousands(char[hasatleast 27], int64_t);
|
||||
char *FormatUint64Thousands(char[hasatleast 27], uint64_t);
|
||||
size_t int64toarray_radix10(int64_t, char[hasatleast 21]);
|
||||
size_t uint64toarray_radix10(uint64_t, char[hasatleast 21]);
|
||||
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/fmt/itoa.h"
|
||||
|
||||
size_t uint64toarray_fixed16(uint64_t x, char b[hasatleast 17], uint8_t k) {
|
||||
int i;
|
||||
char *p;
|
||||
assert(k <= 64 && !(k & 3));
|
||||
for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
||||
|
|
183
libc/fmt/kerrornameslong.S
Normal file
183
libc/fmt/kerrornameslong.S
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 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/macros.internal.h"
|
||||
|
||||
.macro .e e s
|
||||
.long \e - kErrorNamesLong
|
||||
.long 1f - kErrorNamesLong
|
||||
.rodata.str1.1
|
||||
1: .asciz "\s"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
.section .rodata
|
||||
.align 4
|
||||
kErrorNamesLong:
|
||||
.e EPIPE,"EPIPE[Broken pipe]"
|
||||
.e ENODEV,"ENODEV[No such device]"
|
||||
.e EINVAL,"EINVAL[Invalid argument]"
|
||||
.e EINTR,"EINTR[Interrupted system call]"
|
||||
.e ENOTBLK,"ENOTBLK[Block device required]"
|
||||
.e ENOSYS,"ENOSYS[Function not implemented]"
|
||||
.e EHOSTUNREACH,"EHOSTUNREACH[No route to host]"
|
||||
.e ESRCH,"ESRCH[No such process]"
|
||||
.e EUSERS,"EUSERS[Too many users]"
|
||||
.e EXDEV,"EXDEV[Cross-device link]"
|
||||
.e E2BIG,"E2BIG[Arg list too long]"
|
||||
.e EREMOTE,"EREMOTE[Object is remote]"
|
||||
.e ECHILD,"ECHILD[No child processes]"
|
||||
.e EMSGSIZE,"EMSGSIZE[Message too long]"
|
||||
.e ENOTEMPTY,"ENOTEMPTY[Directory not empty]"
|
||||
.e ENOBUFS,"ENOBUFS[No buffer space available]"
|
||||
.e ELOOP,"ELOOP[Too many symbolic links encountered]"
|
||||
.e EAFNOSUPPORT,"EAFNOSUPPORT[Address family not supported by protocol]"
|
||||
.e EHOSTDOWN,"EHOSTDOWN[Host is down]"
|
||||
.e EPFNOSUPPORT,"EPFNOSUPPORT[Protocol family not supported]"
|
||||
.e ENOPROTOOPT,"ENOPROTOOPT[Protocol not available]"
|
||||
.e EBUSY,"EBUSY[Device or resource busy]"
|
||||
.e EWOULDBLOCK,"EWOULDBLOCK[Operation would block]"
|
||||
.e EBADFD,"EBADFD[File descriptor in bad state]"
|
||||
.e EISCONN,"EISCONN[Transport endpoint is already connected]"
|
||||
.e ESHUTDOWN,"ESHUTDOWN[Cannot send after transport endpoint shutdown]"
|
||||
.e ENONET,"ENONET[Machine is not on the network]"
|
||||
.e EBADE,"EBADE[Invalid exchange]"
|
||||
.e EBADF,"EBADF[Bad file number]"
|
||||
.e EMULTIHOP,"EMULTIHOP[Multihop attempted]"
|
||||
.e EIO,"EIO[I/O error]"
|
||||
.e EUNATCH,"EUNATCH[Protocol driver not attached]"
|
||||
.e EPROTOTYPE,"EPROTOTYPE[Protocol wrong type for socket]"
|
||||
.e ENOSPC,"ENOSPC[No space left on device]"
|
||||
.e ENOEXEC,"ENOEXEC[Exec format error]"
|
||||
.e EALREADY,"EALREADY[Operation already in progress]"
|
||||
.e ENETDOWN,"ENETDOWN[Network is down]"
|
||||
.e ENOTNAM,"ENOTNAM[Not a XENIX named type file]"
|
||||
.e EACCES,"EACCES[Permission denied]"
|
||||
.e ELNRNG,"ELNRNG[Link number out of range]"
|
||||
.e EILSEQ,"EILSEQ[Illegal byte sequence]"
|
||||
.e ENOTDIR,"ENOTDIR[Not a directory]"
|
||||
.e ENOTUNIQ,"ENOTUNIQ[Name not unique on network]"
|
||||
.e EPERM,"EPERM[Operation not permitted]"
|
||||
.e EDOM,"EDOM[Math argument out of domain of func]"
|
||||
.e EXFULL,"EXFULL[Exchange full]"
|
||||
.e ECONNREFUSED,"ECONNREFUSED[Connection refused]"
|
||||
.e EISDIR,"EISDIR[Is a directory]"
|
||||
.e EPROTONOSUPPORT,"EPROTONOSUPPORT[Protocol not supported]"
|
||||
.e EROFS,"EROFS[Read-only file system]"
|
||||
.e EADDRNOTAVAIL,"EADDRNOTAVAIL[Cannot assign requested address]"
|
||||
.e EIDRM,"EIDRM[Identifier removed]"
|
||||
.e ECOMM,"ECOMM[Communication error on send]"
|
||||
.e ESRMNT,"ESRMNT[Srmount error]"
|
||||
.e EREMOTEIO,"EREMOTEIO[Remote I/O error]"
|
||||
.e EL3RST,"EL3RST[Level 3 reset]"
|
||||
.e EBADMSG,"EBADMSG[Not a data message]"
|
||||
.e ENFILE,"ENFILE[File table overflow]"
|
||||
.e ELIBMAX,"ELIBMAX[Attempting to link in too many shared libraries]"
|
||||
.e ESPIPE,"ESPIPE[Illegal seek]"
|
||||
.e ENOLINK,"ENOLINK[Link has been severed]"
|
||||
.e ENETRESET,"ENETRESET[Network dropped connection because of reset]"
|
||||
.e ETIMEDOUT,"ETIMEDOUT[Connection timed out]"
|
||||
.e ENOENT,"ENOENT[No such file or directory]"
|
||||
.e EEXIST,"EEXIST[File exists]"
|
||||
.e EDQUOT,"EDQUOT[Quota exceeded]"
|
||||
.e ENOSTR,"ENOSTR[Device not a stream]"
|
||||
.e EBADSLT,"EBADSLT[Invalid slot]"
|
||||
.e EBADRQC,"EBADRQC[Invalid request code]"
|
||||
.e ELIBACC,"ELIBACC[Can not access a needed shared library]"
|
||||
.e EFAULT,"EFAULT[Bad address]"
|
||||
.e EFBIG,"EFBIG[File too large]"
|
||||
.e EDEADLK,"EDEADLK[Resource deadlock would occur]"
|
||||
.e ENOTCONN,"ENOTCONN[Transport endpoint is not connected]"
|
||||
.e EDESTADDRREQ,"EDESTADDRREQ[Destination address required]"
|
||||
.e ELIBSCN,"ELIBSCN[.lib section in a.out corrupted]"
|
||||
.e ENOLCK,"ENOLCK[No record locks available]"
|
||||
.e EISNAM,"EISNAM[Is a named type file]"
|
||||
.e ECONNABORTED,"ECONNABORTED[Software caused connection abort]"
|
||||
.e ENETUNREACH,"ENETUNREACH[Network is unreachable]"
|
||||
.e ESTALE,"ESTALE[Stale NFS file handle]"
|
||||
.e ENOSR,"ENOSR[Out of streams resources]"
|
||||
.e ENOMEM,"ENOMEM[Out of memory]"
|
||||
.e ENOTSOCK,"ENOTSOCK[Socket operation on non-socket]"
|
||||
.e ESTRPIPE,"ESTRPIPE[Streams pipe error]"
|
||||
.e EMLINK,"EMLINK[Too many links]"
|
||||
.e ERANGE,"ERANGE[Math result not representable]"
|
||||
.e ELIBEXEC,"ELIBEXEC[Cannot exec a shared library directly]"
|
||||
.e EL3HLT,"EL3HLT[Level 3 halted]"
|
||||
.e ECONNRESET,"ECONNRESET[Connection reset by peer]"
|
||||
.e EADDRINUSE,"EADDRINUSE[Address already in use]"
|
||||
.e EOPNOTSUPP,"EOPNOTSUPP[Operation not supported on transport endpoint]"
|
||||
.e EREMCHG,"EREMCHG[Remote address changed]"
|
||||
.e EAGAIN,"EAGAIN[Try again]"
|
||||
.e ENAMETOOLONG,"ENAMETOOLONG[File name too long]"
|
||||
.e ENOTTY,"ENOTTY[Not a typewriter]"
|
||||
.e ERESTART,"ERESTART[Interrupted system call should be restarted]"
|
||||
.e ESOCKTNOSUPPORT,"ESOCKTNOSUPPORT[Socket type not supported]"
|
||||
.e ETIME,"ETIME[Timer expired]"
|
||||
.e ETOOMANYREFS,"ETOOMANYREFS[Too many references: cannot splice]"
|
||||
.e EMFILE,"EMFILE[Too many open files]"
|
||||
.e ETXTBSY,"ETXTBSY[Text file busy]"
|
||||
.e EINPROGRESS,"EINPROGRESS[Operation now in progress]"
|
||||
.e ENXIO,"ENXIO[No such device or address]"
|
||||
.e ENOTSUP,"ENOTSUP[Operation not supported]"
|
||||
.e EPROTO,"EPROTO[Protocol error]"
|
||||
.e ENOMSG,"ENOMSG[No message of desired type]"
|
||||
.e ENODATA,"ENODATA[No data available]"
|
||||
.e EOVERFLOW,"EOVERFLOW[Value too large for defined data type]"
|
||||
.e ENOMEDIUM,"ENOMEDIUM[No medium found]"
|
||||
.e EMEDIUMTYPE,"EMEDIUMTYPE[Wrong medium type]"
|
||||
.e ECANCELED,"ECANCELED[Operation Canceled]"
|
||||
.e EOWNERDEAD,"EOWNERDEAD[Owner died]"
|
||||
.e ENOTRECOVERABLE,"ENOTRECOVERABLE[State not recoverable]"
|
||||
.e EOWNERDEAD,"EOWNERDEAD[Process died with the lock]"
|
||||
.e ENOTRECOVERABLE,"ENOTRECOVERABLE[Lock is not recoverable]"
|
||||
.e EFTYPE,"EFTYPE[Inappropriate file type or format]"
|
||||
.e EAUTH,"EAUTH[Authentication error]"
|
||||
.e EBADRPC,"EBADRPC[RPC struct is bad]"
|
||||
.e ENEEDAUTH,"ENEEDAUTH[Need authenticator]"
|
||||
.e ENOATTR,"ENOATTR[Attribute not found]"
|
||||
.e EPROCUNAVAIL,"EPROCUNAVAIL[Bad procedure for program]"
|
||||
.e EPROGMISMATCH,"EPROGMISMATCH[Program version wrong]"
|
||||
.e EPROGUNAVAIL,"EPROGUNAVAIL[RPC prog. not avail]"
|
||||
.e ERPCMISMATCH,"ERPCMISMATCH[RPC version wrong]"
|
||||
.e EPROCLIM,"EPROCLIM[Too many processes]"
|
||||
.e EBADARCH,"EBADARCH[Bad CPU type in executable]"
|
||||
.e EBADEXEC,"EBADEXEC[Bad executable (or shared library)]"
|
||||
.e EBADMACHO,"EBADMACHO[Malformed Mach-o file]"
|
||||
.e EDEVERR,"EDEVERR[Device error]"
|
||||
.e ENOPOLICY,"ENOPOLICY[Policy not found]"
|
||||
.e EPWROFF,"EPWROFF[Device power is off]"
|
||||
.e ESHLIBVERS,"ESHLIBVERS[Shared library version mismatch]"
|
||||
.e ENOANO,"ENOANO[No anode]"
|
||||
.e EADV,"EADV[Advertise error]"
|
||||
.e EL2HLT,"EL2HLT[Level 2 halted]"
|
||||
.e EDOTDOT,"EDOTDOT[RFS specific error]"
|
||||
.e ENOPKG,"ENOPKG[Package not installed]"
|
||||
.e EBADR,"EBADR[Invalid request descriptor]"
|
||||
.e ENOCSI,"ENOCSI[No CSI structure available]"
|
||||
.e ENOKEY,"ENOKEY[Required key not available]"
|
||||
.e EUCLEAN,"EUCLEAN[Structure needs cleaning]"
|
||||
.e ECHRNG,"ECHRNG[Channel number out of range]"
|
||||
.e EL2NSYNC,"EL2NSYNC[Level 2 not synchronized]"
|
||||
.e EKEYEXPIRED,"EKEYEXPIRED[Key has expired]"
|
||||
.e ENAVAIL,"ENAVAIL[No XENIX semaphores available]"
|
||||
.e EKEYREVOKED,"EKEYREVOKED[Key has been revoked]"
|
||||
.e ELIBBAD,"ELIBBAD[Accessing a corrupted shared library]"
|
||||
.e EKEYREJECTED,"EKEYREJECTED[Key was rejected by service]"
|
||||
.e ERFKILL,"ERFKILL[Operation not possible due to RF-kill]"
|
||||
.long 0
|
||||
.endobj kErrorNamesLong,globl,hidden
|
|
@ -27,10 +27,13 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
extern const struct Error {
|
||||
struct Error {
|
||||
int x;
|
||||
int s;
|
||||
} kErrorNames[];
|
||||
};
|
||||
|
||||
extern const struct Error kErrorNames[];
|
||||
extern const struct Error kErrorNamesLong[];
|
||||
|
||||
static const char *GetErrorName(long x) {
|
||||
int i;
|
||||
|
@ -44,6 +47,20 @@ static const char *GetErrorName(long x) {
|
|||
return "EUNKNOWN";
|
||||
}
|
||||
|
||||
static const char *GetErrorNameLong(long x) {
|
||||
int i;
|
||||
if (x) {
|
||||
for (i = 0; kErrorNamesLong[i].x; ++i) {
|
||||
if (x ==
|
||||
*(const long *)((uintptr_t)kErrorNamesLong + kErrorNamesLong[i].x)) {
|
||||
return (const char *)((uintptr_t)kErrorNamesLong +
|
||||
kErrorNamesLong[i].s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "EUNKNOWN[No error information]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts errno value to string.
|
||||
* @return 0 on success, or error code
|
||||
|
@ -52,7 +69,11 @@ int strerror_r(int err, char *buf, size_t size) {
|
|||
char *p;
|
||||
const char *s;
|
||||
err &= 0xFFFF;
|
||||
s = GetErrorName(err);
|
||||
if (IsTiny()) {
|
||||
s = GetErrorName(err);
|
||||
} else {
|
||||
s = GetErrorNameLong(err);
|
||||
}
|
||||
p = buf;
|
||||
if (strlen(s) + 1 + 5 + 1 + 1 <= size) {
|
||||
p = stpcpy(p, s);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 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 │
|
||||
|
@ -16,25 +16,27 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/carsort.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Sorts int32 key-value arrays of trivial size.
|
||||
* Removes file extension.
|
||||
*
|
||||
* @see test/libc/alg/carsort_test.c
|
||||
* @see carsort1000() if larger
|
||||
* @param s is mutated
|
||||
* @return s
|
||||
*/
|
||||
textstartup void carsort100(size_t n, int32_t a[n][2]) {
|
||||
int32_t t[2];
|
||||
unsigned i, j;
|
||||
for (i = 1; i < n; ++i) {
|
||||
j = i;
|
||||
memcpy(t, a[i], sizeof(t));
|
||||
while (j > 0 && t[0] < a[j - 1][0]) {
|
||||
memcpy(a[j], a[j - 1], sizeof(t));
|
||||
--j;
|
||||
char *stripext(char *s) {
|
||||
size_t i;
|
||||
for (i = strlen(s); i--;) {
|
||||
switch (s[i]) {
|
||||
case '.':
|
||||
s[i] = 0;
|
||||
return s;
|
||||
case '/':
|
||||
return s;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
memcpy(a[j], t, sizeof(t));
|
||||
}
|
||||
return s;
|
||||
}
|
|
@ -37,21 +37,24 @@
|
|||
* @see strtoumax()
|
||||
*/
|
||||
intmax_t strtoimax(const char *s, char **endptr, int base) {
|
||||
char t = 0;
|
||||
int d, c = *s;
|
||||
intmax_t x = 0;
|
||||
CONSUME_SPACES(s, c);
|
||||
GET_SIGN(s, c, d);
|
||||
GET_RADIX(s, c, base);
|
||||
if ((c = kBase36[c & 255]) && --c < base) {
|
||||
do {
|
||||
if (__builtin_mul_overflow(x, base, &x) ||
|
||||
__builtin_add_overflow(x, c * d, &x)) {
|
||||
x = d > 0 ? INTMAX_MAX : INTMAX_MIN;
|
||||
errno = ERANGE;
|
||||
break;
|
||||
}
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
if (!((t |= 1) & 2)) {
|
||||
do {
|
||||
if (__builtin_mul_overflow(x, base, &x) ||
|
||||
__builtin_add_overflow(x, c * d, &x)) {
|
||||
x = d > 0 ? INTMAX_MAX : INTMAX_MIN;
|
||||
errno = ERANGE;
|
||||
t |= 2;
|
||||
}
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
}
|
||||
if (endptr) *endptr = s;
|
||||
if (t && endptr) *endptr = s;
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,16 @@
|
|||
/**
|
||||
* Decodes signed integer from ASCII string.
|
||||
*
|
||||
* atoi 10⁸ 22𝑐 7𝑛𝑠
|
||||
* strtol 10⁸ 37𝑐 12𝑛𝑠
|
||||
* strtoul 10⁸ 35𝑐 11𝑛𝑠
|
||||
* wcstol 10⁸ 30𝑐 10𝑛𝑠
|
||||
* wcstoul 10⁸ 30𝑐 10𝑛𝑠
|
||||
* strtoimax 10⁸ 80𝑐 26𝑛𝑠
|
||||
* strtoumax 10⁸ 78𝑐 25𝑛𝑠
|
||||
* wcstoimax 10⁸ 77𝑐 25𝑛𝑠
|
||||
* wcstoumax 10⁸ 76𝑐 25𝑛𝑠
|
||||
*
|
||||
* @param s is a non-null nul-terminated string
|
||||
* @param endptr if non-null will always receive a pointer to the char
|
||||
* following the last one this function processed, which is usually
|
||||
|
@ -36,21 +46,24 @@
|
|||
* @return the decoded signed saturated number
|
||||
*/
|
||||
long strtol(const char *s, char **endptr, int base) {
|
||||
char t = 0;
|
||||
long x = 0;
|
||||
int d, c = *s;
|
||||
CONSUME_SPACES(s, c);
|
||||
GET_SIGN(s, c, d);
|
||||
GET_RADIX(s, c, base);
|
||||
if ((c = kBase36[c & 255]) && --c < base) {
|
||||
do {
|
||||
if (__builtin_mul_overflow(x, base, &x) ||
|
||||
__builtin_add_overflow(x, c * d, &x)) {
|
||||
x = d > 0 ? LONG_MAX : LONG_MIN;
|
||||
errno = ERANGE;
|
||||
break;
|
||||
}
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
if (!((t |= 1) & 2)) {
|
||||
do {
|
||||
if (__builtin_mul_overflow(x, base, &x) ||
|
||||
__builtin_add_overflow(x, c * d, &x)) {
|
||||
x = d > 0 ? LONG_MAX : LONG_MIN;
|
||||
errno = ERANGE;
|
||||
t |= 2;
|
||||
}
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
}
|
||||
if (endptr) *endptr = s;
|
||||
if (t && endptr) *endptr = s;
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define COSMOPOLITAN_LIBC_FMT_STRTOL_H_
|
||||
|
||||
#define CONSUME_SPACES(s, c) \
|
||||
if (endptr) *endptr = s; \
|
||||
while (c == ' ' || c == '\t') c = *++s
|
||||
|
||||
#define GET_SIGN(s, c, d) \
|
||||
|
@ -11,6 +12,7 @@
|
|||
#define GET_RADIX(s, c, r) \
|
||||
if (!(2 <= r && r <= 36)) { \
|
||||
if (c == '0') { \
|
||||
t |= 1; \
|
||||
c = *++s; \
|
||||
if (c == 'x' || c == 'X') { \
|
||||
c = *++s; \
|
||||
|
@ -25,6 +27,7 @@
|
|||
r = 10; \
|
||||
} \
|
||||
} else if (c == '0') { \
|
||||
t |= 1; \
|
||||
c = *++s; \
|
||||
if ((r == 2 && (c == 'b' || c == 'B')) || \
|
||||
(r == 16 && (c == 'x' || c == 'X'))) { \
|
||||
|
|
|
@ -35,17 +35,19 @@
|
|||
* @return decoded integer mod 2⁶⁴ negated if leading `-`
|
||||
*/
|
||||
unsigned long strtoul(const char *s, char **endptr, int base) {
|
||||
char t = 0;
|
||||
int d, c = *s;
|
||||
unsigned long x = 0;
|
||||
CONSUME_SPACES(s, c);
|
||||
GET_SIGN(s, c, d);
|
||||
GET_RADIX(s, c, base);
|
||||
if ((c = kBase36[c & 255]) && --c < base) {
|
||||
t |= 1;
|
||||
do {
|
||||
x *= base;
|
||||
x += c;
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
if (endptr) *endptr = s;
|
||||
if (t && endptr) *endptr = s;
|
||||
return d > 0 ? x : -x;
|
||||
}
|
||||
|
|
|
@ -35,17 +35,19 @@
|
|||
* @see strtoimax()
|
||||
*/
|
||||
uintmax_t strtoumax(const char *s, char **endptr, int base) {
|
||||
char t = 0;
|
||||
int d, c = *s;
|
||||
uintmax_t x = 0;
|
||||
CONSUME_SPACES(s, c);
|
||||
GET_SIGN(s, c, d);
|
||||
GET_RADIX(s, c, base);
|
||||
if ((c = kBase36[c & 255]) && --c < base) {
|
||||
t |= 1;
|
||||
do {
|
||||
x *= base;
|
||||
x += c;
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
if (endptr) *endptr = s;
|
||||
if (t && endptr) *endptr = s;
|
||||
return d > 0 ? x : -x;
|
||||
}
|
||||
|
|
|
@ -37,25 +37,24 @@
|
|||
* @see strtoumax()
|
||||
*/
|
||||
intmax_t wcstoimax(const wchar_t *s, wchar_t **endptr, int base) {
|
||||
int c, d;
|
||||
intmax_t x;
|
||||
c = *s;
|
||||
char t = 0;
|
||||
intmax_t x = 0;
|
||||
int d, c = *s;
|
||||
CONSUME_SPACES(s, c);
|
||||
GET_SIGN(s, c, d);
|
||||
GET_RADIX(s, c, base);
|
||||
x = 0;
|
||||
if ((c = kBase36[c & 255]) && --c < base) {
|
||||
do {
|
||||
if (__builtin_mul_overflow(x, base, &x) ||
|
||||
__builtin_add_overflow(x, c * d, &x)) {
|
||||
x = d > 0 ? INTMAX_MAX : INTMAX_MIN;
|
||||
errno = ERANGE;
|
||||
break;
|
||||
}
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
if (endptr) {
|
||||
*endptr = s;
|
||||
if (!((t |= 1) & 2)) {
|
||||
do {
|
||||
if (__builtin_mul_overflow(x, base, &x) ||
|
||||
__builtin_add_overflow(x, c * d, &x)) {
|
||||
x = d > 0 ? INTMAX_MAX : INTMAX_MIN;
|
||||
errno = ERANGE;
|
||||
t |= 2;
|
||||
}
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
}
|
||||
if (t && endptr) *endptr = s;
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -36,21 +36,24 @@
|
|||
* @return the decoded signed saturated number
|
||||
*/
|
||||
long wcstol(const wchar_t *s, wchar_t **endptr, int base) {
|
||||
char t = 0;
|
||||
long x = 0;
|
||||
int d, c = *s;
|
||||
CONSUME_SPACES(s, c);
|
||||
GET_SIGN(s, c, d);
|
||||
GET_RADIX(s, c, base);
|
||||
if ((c = kBase36[c & 255]) && --c < base) {
|
||||
do {
|
||||
if (__builtin_mul_overflow(x, base, &x) ||
|
||||
__builtin_add_overflow(x, c * d, &x)) {
|
||||
x = d > 0 ? LONG_MAX : LONG_MIN;
|
||||
errno = ERANGE;
|
||||
break;
|
||||
}
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
if (!((t |= 1) & 2)) {
|
||||
do {
|
||||
if (__builtin_mul_overflow(x, base, &x) ||
|
||||
__builtin_add_overflow(x, c * d, &x)) {
|
||||
x = d > 0 ? LONG_MAX : LONG_MIN;
|
||||
errno = ERANGE;
|
||||
t |= 2;
|
||||
}
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
}
|
||||
if (endptr) *endptr = s;
|
||||
if (t && endptr) *endptr = s;
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -35,17 +35,19 @@
|
|||
* @return decoded integer mod 2⁶⁴ negated if leading `-`
|
||||
*/
|
||||
unsigned long wcstoul(const wchar_t *s, wchar_t **endptr, int base) {
|
||||
char t = 0;
|
||||
int d, c = *s;
|
||||
unsigned long x = 0;
|
||||
CONSUME_SPACES(s, c);
|
||||
GET_SIGN(s, c, d);
|
||||
GET_RADIX(s, c, base);
|
||||
if ((c = kBase36[c & 255]) && --c < base) {
|
||||
t |= 1;
|
||||
do {
|
||||
x *= base;
|
||||
x += c;
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
if (endptr) *endptr = s;
|
||||
if (t && endptr) *endptr = s;
|
||||
return d > 0 ? x : -x;
|
||||
}
|
||||
|
|
|
@ -35,21 +35,19 @@
|
|||
* @see strtoimax()
|
||||
*/
|
||||
uintmax_t wcstoumax(const wchar_t *s, wchar_t **endptr, int base) {
|
||||
int c, d;
|
||||
uintmax_t x;
|
||||
c = *s;
|
||||
char t = 0;
|
||||
int d, c = *s;
|
||||
uintmax_t x = 0;
|
||||
CONSUME_SPACES(s, c);
|
||||
GET_SIGN(s, c, d);
|
||||
GET_RADIX(s, c, base);
|
||||
x = 0;
|
||||
if ((c = kBase36[c & 255]) && --c < base) {
|
||||
t |= 1;
|
||||
do {
|
||||
x *= base;
|
||||
x += c;
|
||||
} while ((c = kBase36[*++s & 255]) && --c < base);
|
||||
}
|
||||
if (endptr) {
|
||||
*endptr = s;
|
||||
}
|
||||
if (t && endptr) *endptr = s;
|
||||
return d > 0 ? x : -x;
|
||||
}
|
||||
|
|
|
@ -644,6 +644,10 @@ typedef uint64_t uintmax_t;
|
|||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||
#endif
|
||||
|
||||
#ifdef __llvm__
|
||||
#define __builtin_ia32_movntdq(x, y) (*(x) = (y))
|
||||
#endif
|
||||
|
||||
#ifndef _Section
|
||||
#if !defined(__STRICT_ANSI__) && !defined(__APPLE__)
|
||||
#define _Section(s) __attribute__((__section__(s)))
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
#endif
|
||||
|
||||
#define BIGPAGESIZE 0x200000
|
||||
#define STACKSIZE 0x100000
|
||||
#define STACKSIZE 0x200000
|
||||
#define FRAMESIZE 0x10000 /* 8086 */
|
||||
#define PAGESIZE 0x1000 /* i386+ */
|
||||
#define BUFSIZ 0x1000 /* best stdio default */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/dce.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/hook/hook.internal.h"
|
||||
|
@ -32,12 +33,16 @@
|
|||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "third_party/dlmalloc/dlmalloc.internal.h"
|
||||
|
||||
#define COOKIE 21578
|
||||
|
||||
STATIC_YOINK("_init_asan");
|
||||
|
||||
/**
|
||||
|
@ -85,6 +90,8 @@ STATIC_YOINK("_init_asan");
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
|
||||
struct AsanSourceLocation {
|
||||
const char *filename;
|
||||
int line;
|
||||
|
@ -129,6 +136,28 @@ static uint64_t __asan_rounddown2pow(uint64_t x) {
|
|||
return x ? 1ull << __asan_bsrl(x) : 0;
|
||||
}
|
||||
|
||||
static uint64_t __asan_encodeutf8(unsigned c) {
|
||||
static const unsigned short kTpEnc[32 - 7] = {
|
||||
1 | 0300 << 8, 1 | 0300 << 8, 1 | 0300 << 8, 1 | 0300 << 8, 2 | 0340 << 8,
|
||||
2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 3 | 0360 << 8,
|
||||
3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 4 | 0370 << 8,
|
||||
4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 5 | 0374 << 8,
|
||||
5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8,
|
||||
};
|
||||
int e, n;
|
||||
unsigned long long w;
|
||||
if (c < 0200) return c;
|
||||
e = kTpEnc[__asan_bsrl(c) - 7];
|
||||
n = e & 0xff;
|
||||
w = 0;
|
||||
do {
|
||||
w |= 0200 | (c & 077);
|
||||
w <<= 8;
|
||||
c >>= 6;
|
||||
} while (--n);
|
||||
return c | w | e >> 8;
|
||||
}
|
||||
|
||||
static size_t __asan_strlen(const char *s) {
|
||||
size_t n = 0;
|
||||
while (*s++) ++n;
|
||||
|
@ -299,20 +328,68 @@ static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *__asan_uint2str(char *p, uint64_t i) {
|
||||
int j = 0;
|
||||
static char *__asan_uintcpy(char p[hasatleast 21], uint64_t x) {
|
||||
char t;
|
||||
size_t i, a, b;
|
||||
i = 0;
|
||||
do {
|
||||
p[j++] = i % 10 + '0';
|
||||
i /= 10;
|
||||
} while (i > 0);
|
||||
reverse(p, j);
|
||||
return p + j;
|
||||
p[i++] = x % 10 + '0';
|
||||
x = x / 10;
|
||||
} while (x > 0);
|
||||
p[i] = '\0';
|
||||
if (i) {
|
||||
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
||||
t = p[a];
|
||||
p[a] = p[b];
|
||||
p[b] = t;
|
||||
}
|
||||
}
|
||||
return p + i;
|
||||
}
|
||||
|
||||
static char *__asan_intcpy(char *p, int64_t i) {
|
||||
if (i >= 0) return __asan_uint2str(p, i);
|
||||
*p++ = '-';
|
||||
return __asan_uint2str(p, -i);
|
||||
static char *__asan_intcpy(char p[hasatleast 21], int64_t x) {
|
||||
if (x < 0) *p++ = '-', x = -(uint64_t)x;
|
||||
return __asan_uintcpy(p, x);
|
||||
}
|
||||
|
||||
privileged noinline wontreturn void __asan_exit(int rc) {
|
||||
if (!IsWindows()) {
|
||||
asm volatile("syscall"
|
||||
: /* no outputs */
|
||||
: "a"(__NR_exit_group), "D"(rc)
|
||||
: "memory");
|
||||
unreachable;
|
||||
} else {
|
||||
ExitProcess(rc);
|
||||
}
|
||||
}
|
||||
|
||||
privileged noinline ssize_t __asan_write(const void *data, size_t size) {
|
||||
ssize_t rc;
|
||||
uint32_t wrote;
|
||||
if (!IsWindows()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(rc)
|
||||
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
|
||||
: "rcx", "r11", "memory");
|
||||
return rc;
|
||||
} else {
|
||||
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
|
||||
return wrote;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t __asan_write_string(const char *s) {
|
||||
return __asan_write(s, __asan_strlen(s));
|
||||
}
|
||||
|
||||
wontreturn void __asan_die(const char *msg) {
|
||||
__asan_write_string(msg);
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
__asan_exit(134);
|
||||
}
|
||||
|
||||
void __asan_poison(uintptr_t p, size_t n, int t) {
|
||||
|
@ -320,13 +397,16 @@ void __asan_poison(uintptr_t p, size_t n, int t) {
|
|||
k = p & 7;
|
||||
s = (signed char *)((p >> 3) + 0x7fff8000);
|
||||
if (UNLIKELY(k)) {
|
||||
if (n && (!*s || *s > k) && 8 - k >= n) *s = k;
|
||||
++s, n -= MIN(8 - k, n);
|
||||
if (k < *s && *s <= k + n) *s = k;
|
||||
n -= MIN(8 - k, n);
|
||||
s += 1;
|
||||
}
|
||||
__asan_memset(s, t, n >> 3);
|
||||
if ((k = n & 7)) {
|
||||
s += n >> 3;
|
||||
if (*s < 0 || 0 < *s && *s <= k) *s = t;
|
||||
if (*s >= 0) {
|
||||
*s = kAsanHeapOverrun;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,54 +415,126 @@ void __asan_unpoison(uintptr_t p, size_t n) {
|
|||
k = p & 7;
|
||||
s = (signed char *)((p >> 3) + 0x7fff8000);
|
||||
if (UNLIKELY(k)) {
|
||||
if (n) *s = 0;
|
||||
++s, n -= MIN(8 - k, n);
|
||||
if (!n) return;
|
||||
if (k + n < 8) {
|
||||
*s = MAX(*s, k + n);
|
||||
return;
|
||||
} else {
|
||||
*s = 0;
|
||||
}
|
||||
n -= MIN(8 - k, n);
|
||||
s += 1;
|
||||
}
|
||||
__asan_memset(s, 0, n >> 3);
|
||||
if ((k = n & 7)) {
|
||||
s += n >> 3;
|
||||
if (*s && *s < k) *s = k;
|
||||
if (*s < 0) {
|
||||
*s = k;
|
||||
} else if (*s > 0) {
|
||||
*s = MAX(*s, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool __asan_is_valid(const void *p, size_t n) {
|
||||
signed char k, *s, *e;
|
||||
if (n) {
|
||||
if (p) {
|
||||
k = (uintptr_t)p & 7;
|
||||
s = (signed char *)(((uintptr_t)p >> 3) + 0x7fff8000);
|
||||
if (UNLIKELY(k)) {
|
||||
if (n && !(!*s || *s >= k + n)) return false;
|
||||
++s, n -= MIN(8 - k, n);
|
||||
}
|
||||
e = s;
|
||||
k = n & 7;
|
||||
e += n >> 3;
|
||||
for (; s + 8 <= e; s += 8) {
|
||||
if ((uint64_t)(255 & s[0]) << 000 | (uint64_t)(255 & s[1]) << 010 |
|
||||
(uint64_t)(255 & s[2]) << 020 | (uint64_t)(255 & s[3]) << 030 |
|
||||
(uint64_t)(255 & s[4]) << 040 | (uint64_t)(255 & s[5]) << 050 |
|
||||
(uint64_t)(255 & s[6]) << 060 | (uint64_t)(255 & s[7]) << 070) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (s < e) {
|
||||
if (*s++) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (k) {
|
||||
if (!(!*s || *s >= k)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
static inline bool __asan_is_mapped(int x) {
|
||||
int i;
|
||||
struct MemoryIntervals *m;
|
||||
m = weaken(_mmi);
|
||||
i = FindMemoryInterval(m, x);
|
||||
return i < m->i && m->p[i].x <= x && x <= m->p[i].y;
|
||||
}
|
||||
|
||||
static inline bool __asan_is_image(const unsigned char *p) {
|
||||
return _base <= p && p < _end;
|
||||
}
|
||||
|
||||
static inline bool __asan_exists(const void *x) {
|
||||
return __asan_is_image(x) || __asan_is_mapped((intptr_t)x >> 16);
|
||||
}
|
||||
|
||||
static struct AsanFault __asan_fault(signed char *s, char dflt) {
|
||||
struct AsanFault r;
|
||||
if (s[0] < 0) {
|
||||
r.kind = s[0];
|
||||
} else if (((uintptr_t)(s + 1) & (PAGESIZE - 1)) && s[1] < 0) {
|
||||
r.kind = s[1];
|
||||
} else {
|
||||
return true;
|
||||
r.kind = dflt;
|
||||
}
|
||||
r.shadow = s;
|
||||
return r;
|
||||
}
|
||||
|
||||
struct AsanFault __asan_check(const void *p, size_t n) {
|
||||
intptr_t a;
|
||||
uint64_t w;
|
||||
unsigned u, r;
|
||||
signed char k, *s, *e, *f;
|
||||
if (!n) return (struct AsanFault){0};
|
||||
k = (intptr_t)p & 7;
|
||||
a = ((intptr_t)p >> 3) + 0x7fff8000;
|
||||
s = (signed char *)a;
|
||||
if (!__asan_is_mapped(a >> 16)) {
|
||||
return (struct AsanFault){kAsanUnmapped, s};
|
||||
}
|
||||
if (UNLIKELY(k)) {
|
||||
if (!*s) {
|
||||
n -= MIN(8 - k, n);
|
||||
s += 1;
|
||||
} else if (*s > 0 && k + n < 8 && *s >= k + n) {
|
||||
return (struct AsanFault){0};
|
||||
} else {
|
||||
return __asan_fault(s, kAsanHeapOverrun);
|
||||
}
|
||||
}
|
||||
e = s;
|
||||
k = n & 7;
|
||||
e += n >> 3;
|
||||
while (s < e && ((intptr_t)s & 7)) {
|
||||
if (*s++) {
|
||||
return __asan_fault(s - 1, kAsanHeapOverrun);
|
||||
}
|
||||
}
|
||||
for (; s + 8 <= e; s += 8) {
|
||||
if (UNLIKELY(!((a = (intptr_t)s) & 0xffff))) {
|
||||
if (!__asan_is_mapped(a >> 16)) {
|
||||
return (struct AsanFault){kAsanUnmapped, s};
|
||||
}
|
||||
}
|
||||
if ((w = ((uint64_t)(255 & s[0]) << 000 | (uint64_t)(255 & s[1]) << 010 |
|
||||
(uint64_t)(255 & s[2]) << 020 | (uint64_t)(255 & s[3]) << 030 |
|
||||
(uint64_t)(255 & s[4]) << 040 | (uint64_t)(255 & s[5]) << 050 |
|
||||
(uint64_t)(255 & s[6]) << 060 | (uint64_t)(255 & s[7]) << 070))) {
|
||||
s += (unsigned)__builtin_ctzll(w) >> 3;
|
||||
return __asan_fault(s, kAsanHeapOverrun);
|
||||
}
|
||||
}
|
||||
while (s < e) {
|
||||
if (*s++) {
|
||||
return __asan_fault(s - 1, kAsanHeapOverrun);
|
||||
}
|
||||
}
|
||||
if (!k || !*s || k <= *s) {
|
||||
return (struct AsanFault){0};
|
||||
} else {
|
||||
return __asan_fault(s, kAsanHeapOverrun);
|
||||
}
|
||||
}
|
||||
|
||||
void __asan_verify(const void *p, size_t n) {
|
||||
const char *q;
|
||||
struct AsanFault f;
|
||||
if (!(f = __asan_check(p, n)).kind) return;
|
||||
q = UNSHADOW(f.shadow);
|
||||
if ((uintptr_t)q != ((uintptr_t)p & -8) && (uintptr_t)q - (uintptr_t)p < n) {
|
||||
n -= (uintptr_t)q - (uintptr_t)p;
|
||||
p = q;
|
||||
}
|
||||
__asan_report(p, n, "verify", f.kind);
|
||||
}
|
||||
|
||||
bool __asan_is_valid(const void *p, size_t n) {
|
||||
return !__asan_check(p, n).kind;
|
||||
}
|
||||
|
||||
bool __asan_is_valid_iov(const struct iovec *iov, int iovlen) {
|
||||
|
@ -423,10 +575,8 @@ static const char *__asan_dscribe_heap_poison(long c) {
|
|||
}
|
||||
}
|
||||
|
||||
static const char *__asan_describe_access_poison(signed char *p) {
|
||||
int c = p[0];
|
||||
if (1 <= c && c <= 7) c = p[1];
|
||||
switch (c) {
|
||||
static const char *__asan_describe_access_poison(char kind) {
|
||||
switch (kind) {
|
||||
case kAsanHeapFree:
|
||||
return "heap use after free";
|
||||
case kAsanStackFree:
|
||||
|
@ -453,89 +603,163 @@ static const char *__asan_describe_access_poison(signed char *p) {
|
|||
return "unscoped";
|
||||
case kAsanUnmapped:
|
||||
return "unmapped";
|
||||
case kAsanProtected:
|
||||
return "protected";
|
||||
case kAsanStackGuard:
|
||||
return "stack overflow";
|
||||
default:
|
||||
return "poisoned";
|
||||
}
|
||||
}
|
||||
|
||||
static privileged noinline wontreturn void __asan_exit(int rc) {
|
||||
if (!IsWindows()) {
|
||||
asm volatile("syscall"
|
||||
: /* no outputs */
|
||||
: "a"(__NR_exit_group), "D"(rc)
|
||||
: "memory");
|
||||
unreachable;
|
||||
} else {
|
||||
ExitProcess(rc);
|
||||
}
|
||||
}
|
||||
|
||||
static privileged noinline ssize_t __asan_write(const void *data, size_t size) {
|
||||
ssize_t rc;
|
||||
uint32_t wrote;
|
||||
if (!IsWindows()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(rc)
|
||||
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
|
||||
: "rcx", "r11", "memory");
|
||||
return rc;
|
||||
} else {
|
||||
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
|
||||
return wrote;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t __asan_write_string(const char *s) {
|
||||
return __asan_write(s, __asan_strlen(s));
|
||||
}
|
||||
|
||||
static wontreturn void __asan_die(const char *msg) {
|
||||
__asan_write_string(msg);
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
__asan_exit(134);
|
||||
}
|
||||
|
||||
static char *__asan_report_start(char *p) {
|
||||
bool ansi;
|
||||
static bool __asan_ansi(void) {
|
||||
const char *term;
|
||||
term = weaken(getenv) ? weaken(getenv)("TERM") : NULL;
|
||||
ansi = !term || __asan_strcmp(term, "dumb") != 0;
|
||||
return !term || __asan_strcmp(term, "dumb") != 0;
|
||||
}
|
||||
|
||||
static char *__asan_report_start(char *p, bool ansi) {
|
||||
if (ansi) p = __asan_stpcpy(p, "\r\e[J\e[1;91m");
|
||||
p = __asan_stpcpy(p, "asan error");
|
||||
if (ansi) p = __asan_stpcpy(p, "\e[0m");
|
||||
return __asan_stpcpy(p, ": ");
|
||||
}
|
||||
|
||||
static wontreturn void __asan_report_heap_fault(void *addr, long c) {
|
||||
char *p, ibuf[21], buf[256];
|
||||
p = __asan_report_start(buf);
|
||||
p = __asan_stpcpy(p, __asan_dscribe_heap_poison(c));
|
||||
p = __asan_stpcpy(p, " at 0x");
|
||||
static wontreturn void __asan_report_invalid_pointer(void *addr) {
|
||||
char *p;
|
||||
p = __asan_report_start(__fatalbuf, __asan_ansi());
|
||||
p = __asan_stpcpy(p, "invalid pointer 0x");
|
||||
p = __asan_hexcpy(p, (intptr_t)addr, 48);
|
||||
p = __asan_stpcpy(p, " shadow 0x");
|
||||
p = __asan_hexcpy(p, (intptr_t)SHADOW(addr), 48);
|
||||
p = __asan_stpcpy(p, "\r\n");
|
||||
__asan_die(buf);
|
||||
__asan_die(__fatalbuf);
|
||||
}
|
||||
|
||||
static wontreturn void __asan_report_memory_fault(uint8_t *addr, int size,
|
||||
const char *kind) {
|
||||
char *p, ibuf[21], buf[256];
|
||||
p = __asan_report_start(buf);
|
||||
p = __asan_stpcpy(p, __asan_describe_access_poison(SHADOW(addr)));
|
||||
static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) {
|
||||
p = __asan_hexcpy(p, a, 48);
|
||||
*p++ = '-';
|
||||
p = __asan_hexcpy(p, b, 48);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *__asan_format_section(char *p, void *p1, void *p2,
|
||||
const char *name, void *addr) {
|
||||
intptr_t a, b;
|
||||
if ((a = (intptr_t)p1) < (b = (intptr_t)p2)) {
|
||||
p = __asan_format_interval(p, a, b);
|
||||
*p++ = ' ';
|
||||
p = __asan_stpcpy(p, name);
|
||||
if (a <= (intptr_t)addr && (intptr_t)addr <= b) {
|
||||
p = __asan_stpcpy(p, " ←address");
|
||||
}
|
||||
*p++ = '\r';
|
||||
*p++ = '\n';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
wontreturn void __asan_report(void *addr, int size, const char *message,
|
||||
char kind) {
|
||||
bool a;
|
||||
wint_t c;
|
||||
int i, cc;
|
||||
signed char t;
|
||||
uint64_t x, y, z;
|
||||
char *p, *q, *base;
|
||||
struct MemoryIntervals *m;
|
||||
a = __asan_ansi();
|
||||
p = __asan_report_start(__fatalbuf, a);
|
||||
p = __asan_stpcpy(p, __asan_describe_access_poison(kind));
|
||||
p = __asan_stpcpy(p, " ");
|
||||
p = __asan_intcpy(p, size);
|
||||
p = __asan_stpcpy(p, "-byte ");
|
||||
p = __asan_stpcpy(p, kind);
|
||||
p = __asan_stpcpy(p, message);
|
||||
p = __asan_stpcpy(p, " at 0x");
|
||||
p = __asan_hexcpy(p, (uintptr_t)addr, 48);
|
||||
p = __asan_stpcpy(p, " shadow 0x");
|
||||
p = __asan_hexcpy(p, (uintptr_t)SHADOW(addr), 48);
|
||||
p = __asan_stpcpy(p, "\r\n");
|
||||
__asan_die(buf);
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
if (0 < size && size < 80) {
|
||||
base = (char *)addr - ((80 >> 1) - (size >> 1));
|
||||
for (i = 0; i < 80; ++i) {
|
||||
if ((char *)addr <= base + i && base + i < (char *)addr + size) {
|
||||
if (__asan_is_valid(base + i, 1)) {
|
||||
*p++ = '*';
|
||||
} else {
|
||||
*p++ = 'x';
|
||||
}
|
||||
} else {
|
||||
*p++ = ' ';
|
||||
}
|
||||
}
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
for (c = i = 0; i < 80; ++i) {
|
||||
if (!(t = __asan_check(base + i, 1).kind)) {
|
||||
if (a && c != 32) {
|
||||
p = __asan_stpcpy(p, "\e[32m");
|
||||
c = 32;
|
||||
}
|
||||
*p++ = '.';
|
||||
} else {
|
||||
if (a && c != 31) {
|
||||
p = __asan_stpcpy(p, "\e[31m");
|
||||
c = 31;
|
||||
}
|
||||
*p++ = "FFRRUOOGUOUOSMP~"[-t & 15];
|
||||
}
|
||||
}
|
||||
if (a) p = __asan_stpcpy(p, "\e[39m");
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' ';
|
||||
for (; i + 8 <= 80; i += 8) {
|
||||
q = p + 8;
|
||||
*p++ = '|';
|
||||
z = ((intptr_t)(base + i) >> 3) + 0x7fff8000;
|
||||
if (__asan_is_mapped(z >> 16)) {
|
||||
p = __asan_intcpy(p, *(signed char *)z);
|
||||
} else {
|
||||
*p++ = '!';
|
||||
}
|
||||
while (p < q) {
|
||||
*p++ = ' ';
|
||||
}
|
||||
}
|
||||
for (; i < 80; ++i) *p++ = ' ';
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
for (i = 0; i < 80; ++i) {
|
||||
if (__asan_exists(base + i)) {
|
||||
c = kCp437[((unsigned char *)base)[i]];
|
||||
} else {
|
||||
c = u'⋅';
|
||||
}
|
||||
z = __asan_encodeutf8(c);
|
||||
do {
|
||||
*p++ = z;
|
||||
} while ((z >>= 8));
|
||||
}
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
}
|
||||
p = __asan_format_section(p, _base, _etext, ".text", addr);
|
||||
p = __asan_format_section(p, _etext, _edata, ".data", addr);
|
||||
p = __asan_format_section(p, _end, _edata, ".bss", addr);
|
||||
for (m = weaken(_mmi), i = 0; i < m->i; ++i) {
|
||||
x = m->p[i].x;
|
||||
y = m->p[i].y;
|
||||
p = __asan_format_interval(p, x << 16, (y << 16) + (FRAMESIZE - 1));
|
||||
z = (intptr_t)addr >> 16;
|
||||
if (x <= z && z <= y) p = __asan_stpcpy(p, " ←address");
|
||||
z = (((intptr_t)addr >> 3) + 0x7fff8000) >> 16;
|
||||
if (x <= z && z <= y) p = __asan_stpcpy(p, " ←shadow");
|
||||
*p++ = '\r', *p++ = '\n';
|
||||
}
|
||||
*p = 0;
|
||||
__asan_die(__fatalbuf);
|
||||
}
|
||||
|
||||
wontreturn void __asan_report_memory_fault(void *addr, int size,
|
||||
const char *message) {
|
||||
__asan_report(addr, size, message, __asan_fault(SHADOW(addr), -128).kind);
|
||||
}
|
||||
|
||||
const void *__asan_morgue_add(void *p) {
|
||||
|
@ -566,75 +790,108 @@ static void __asan_morgue_flush(void) {
|
|||
}
|
||||
|
||||
static size_t __asan_heap_size(size_t n) {
|
||||
if (n < -8) {
|
||||
if (n <= 0x7fffffffffff) {
|
||||
return __asan_roundup2pow(ROUNDUP(n, 8) + 8);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t __asan_user_size(size_t n) {
|
||||
if (n) {
|
||||
return n;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t __asan_stack_size(void) {
|
||||
extern char ape_stack_memsz[] __attribute__((__weak__));
|
||||
if (ape_stack_memsz) {
|
||||
return (uintptr_t)ape_stack_memsz;
|
||||
} else {
|
||||
return STACKSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline void __asan_write48(char *p, uint64_t x) {
|
||||
uint64_t value, cookie;
|
||||
cookie = COOKIE;
|
||||
cookie ^= x & 0xffff;
|
||||
value = (x & 0xffffffffffff) | cookie << 48;
|
||||
WRITE64BE(p, value);
|
||||
}
|
||||
|
||||
forceinline bool __asan_read48(const char *p, uint64_t *x) {
|
||||
uint64_t value, cookie;
|
||||
value = READ64BE(p);
|
||||
cookie = value >> 48;
|
||||
cookie ^= value & 0xffff;
|
||||
*x = (int64_t)(value << 16) >> 16;
|
||||
return cookie == COOKIE;
|
||||
}
|
||||
|
||||
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun) {
|
||||
char *p;
|
||||
size_t c;
|
||||
char *p, *f;
|
||||
if ((p = weaken(dlmemalign)(a, __asan_heap_size(n)))) {
|
||||
n = __asan_user_size(n);
|
||||
c = weaken(dlmalloc_usable_size)(p);
|
||||
__asan_unpoison((uintptr_t)p, n);
|
||||
__asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */
|
||||
__asan_poison((uintptr_t)p + n, c - n, overrun);
|
||||
__asan_memset(p, 0xF9, n);
|
||||
f = p + c - 8;
|
||||
WRITE64BE(f, n);
|
||||
__asan_write48(p + c - 8, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static size_t __asan_malloc_usable_size(const void *p) {
|
||||
size_t c, n;
|
||||
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
|
||||
if ((n = READ64BE((char *)p + c - 8)) <= c) {
|
||||
return n;
|
||||
} else {
|
||||
__asan_report_heap_fault(p, n);
|
||||
struct AsanFault f;
|
||||
if (!(f = __asan_check(p, 1)).kind) {
|
||||
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
|
||||
if (__asan_read48((char *)p + c - 8, &n) && n <= c) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
__asan_report_invalid_pointer(p);
|
||||
} else {
|
||||
__asan_report_heap_fault(p, 0);
|
||||
__asan_report(p, 1, "heaping", f.kind);
|
||||
}
|
||||
}
|
||||
|
||||
static void __asan_deallocate(char *p, long kind) {
|
||||
size_t c, n;
|
||||
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
|
||||
if ((n = READ64BE(p + c - 8)) <= c) {
|
||||
WRITE64BE(p + c - 8, kind);
|
||||
__asan_poison((uintptr_t)p, c - 8, kind);
|
||||
if (weaken(dlfree)) {
|
||||
if (c <= FRAMESIZE) {
|
||||
p = __asan_morgue_add(p);
|
||||
}
|
||||
weaken(dlfree)(p);
|
||||
if (__asan_read48(p + c - 8, &n) && n <= c) {
|
||||
__asan_poison((uintptr_t)p, c, kind);
|
||||
if (c <= FRAMESIZE) {
|
||||
p = __asan_morgue_add(p);
|
||||
}
|
||||
weaken(dlfree)(p);
|
||||
} else {
|
||||
__asan_report_heap_fault(p, n);
|
||||
__asan_report_invalid_pointer(p);
|
||||
}
|
||||
} else {
|
||||
__asan_report_heap_fault(p, 0);
|
||||
__asan_report_invalid_pointer(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void __asan_free(void *p) {
|
||||
void __asan_free(void *p) {
|
||||
if (!p) return;
|
||||
__asan_deallocate(p, kAsanHeapFree);
|
||||
}
|
||||
|
||||
static void *__asan_memalign(size_t align, size_t size) {
|
||||
void *__asan_memalign(size_t align, size_t size) {
|
||||
return __asan_allocate(align, size, kAsanHeapUnderrun, kAsanHeapOverrun);
|
||||
}
|
||||
|
||||
static void *__asan_malloc(size_t size) {
|
||||
void *__asan_malloc(size_t size) {
|
||||
return __asan_memalign(__BIGGEST_ALIGNMENT__, size);
|
||||
}
|
||||
|
||||
static void *__asan_calloc(size_t n, size_t m) {
|
||||
void *__asan_calloc(size_t n, size_t m) {
|
||||
char *p;
|
||||
if (__builtin_mul_overflow(n, m, &n)) n = -1;
|
||||
if ((p = __asan_malloc(n))) __asan_memset(p, 0, n);
|
||||
|
@ -660,27 +917,27 @@ static void *__asan_realloc_impl(void *p, size_t n,
|
|||
size_t c, m;
|
||||
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
|
||||
f = (char *)p + c - 8;
|
||||
if ((m = READ64BE(f)) <= c) {
|
||||
if (__asan_read48(f, &m) && m <= c) {
|
||||
if (n <= m) { /* shrink */
|
||||
__asan_poison((uintptr_t)p + n, m - n, kAsanHeapOverrun);
|
||||
WRITE64BE(f, n);
|
||||
__asan_write48(f, n);
|
||||
return p;
|
||||
} else if (n <= c - 8) { /* small growth */
|
||||
__asan_unpoison((uintptr_t)p + m, n - m);
|
||||
WRITE64BE(f, n);
|
||||
__asan_write48(f, n);
|
||||
return p;
|
||||
} else { /* exponential growth */
|
||||
return grow(p, n, m);
|
||||
}
|
||||
} else {
|
||||
__asan_report_heap_fault(p, m);
|
||||
__asan_report_invalid_pointer(p);
|
||||
}
|
||||
} else {
|
||||
__asan_report_heap_fault(p, 0);
|
||||
__asan_report_invalid_pointer(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void *__asan_realloc(void *p, size_t n) {
|
||||
void *__asan_realloc(void *p, size_t n) {
|
||||
if (p) {
|
||||
if (n) {
|
||||
return __asan_realloc_impl(p, n, __asan_realloc_grow);
|
||||
|
@ -693,7 +950,7 @@ static void *__asan_realloc(void *p, size_t n) {
|
|||
}
|
||||
}
|
||||
|
||||
static void *__asan_realloc_in_place(void *p, size_t n) {
|
||||
void *__asan_realloc_in_place(void *p, size_t n) {
|
||||
if (p) {
|
||||
return __asan_realloc_impl(p, n, __asan_realloc_nogrow);
|
||||
} else {
|
||||
|
@ -701,15 +958,15 @@ static void *__asan_realloc_in_place(void *p, size_t n) {
|
|||
}
|
||||
}
|
||||
|
||||
static void *__asan_valloc(size_t n) {
|
||||
void *__asan_valloc(size_t n) {
|
||||
return __asan_memalign(PAGESIZE, n);
|
||||
}
|
||||
|
||||
static void *__asan_pvalloc(size_t n) {
|
||||
void *__asan_pvalloc(size_t n) {
|
||||
return __asan_valloc(ROUNDUP(n, PAGESIZE));
|
||||
}
|
||||
|
||||
static int __asan_malloc_trim(size_t pad) {
|
||||
int __asan_malloc_trim(size_t pad) {
|
||||
__asan_morgue_flush();
|
||||
if (weaken(dlmalloc_trim)) {
|
||||
return weaken(dlmalloc_trim)(pad);
|
||||
|
@ -727,9 +984,10 @@ void __asan_stack_free(char *p, size_t size, int classid) {
|
|||
}
|
||||
|
||||
void __asan_handle_no_return(void) {
|
||||
uintptr_t rsp;
|
||||
rsp = (uintptr_t)__builtin_frame_address(0);
|
||||
__asan_unpoison(rsp, ROUNDUP(rsp, STACKSIZE) - rsp);
|
||||
uintptr_t stk, ssz;
|
||||
stk = (uintptr_t)__builtin_frame_address(0);
|
||||
ssz = __asan_stack_size();
|
||||
__asan_unpoison(stk, ROUNDUP(stk, ssz) - stk);
|
||||
}
|
||||
|
||||
void __asan_register_globals(struct AsanGlobal g[], int n) {
|
||||
|
@ -797,14 +1055,6 @@ void __asan_install_malloc_hooks(void) {
|
|||
HOOK(hook_malloc_usable_size, __asan_malloc_usable_size);
|
||||
}
|
||||
|
||||
static bool __asan_is_mapped(int x) {
|
||||
int i;
|
||||
struct MemoryIntervals *m;
|
||||
m = weaken(_mmi);
|
||||
i = weaken(FindMemoryInterval)(m, x);
|
||||
return i < m->i && x >= m->p[i].x && x <= m->p[i].y;
|
||||
}
|
||||
|
||||
void __asan_map_shadow(uintptr_t p, size_t n) {
|
||||
int i, x, a, b;
|
||||
struct DirectMap sm;
|
||||
|
@ -862,17 +1112,22 @@ static textstartup void __asan_shadow_string_list(char **list) {
|
|||
|
||||
static textstartup void __asan_shadow_existing_mappings(void) {
|
||||
size_t i;
|
||||
uintptr_t rsp, stk, ssz;
|
||||
struct MemoryIntervals m;
|
||||
__asan_memcpy(&m, weaken(_mmi), sizeof(m));
|
||||
for (i = 0; i < m.i; ++i) {
|
||||
__asan_map_shadow((uintptr_t)m.p[i].x << 16,
|
||||
(uintptr_t)(m.p[i].y - m.p[i].x + 1) << 16);
|
||||
}
|
||||
rsp = (uintptr_t)__builtin_frame_address(0);
|
||||
ssz = __asan_stack_size();
|
||||
stk = ROUNDDOWN(rsp, ssz);
|
||||
__asan_poison(stk, PAGESIZE, kAsanStackGuard);
|
||||
}
|
||||
|
||||
static textstartup bool IsMemoryManagementRuntimeLinked(void) {
|
||||
return weaken(_mmi) && weaken(sys_mmap) && weaken(MAP_ANONYMOUS) &&
|
||||
weaken(FindMemoryInterval) && weaken(TrackMemoryInterval);
|
||||
weaken(TrackMemoryInterval);
|
||||
}
|
||||
|
||||
textstartup void __asan_init(int argc, char **argv, char **envp,
|
||||
|
@ -886,7 +1141,6 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
|
|||
REQUIRE(_mmi);
|
||||
REQUIRE(sys_mmap);
|
||||
REQUIRE(MAP_ANONYMOUS);
|
||||
REQUIRE(FindMemoryInterval);
|
||||
REQUIRE(TrackMemoryInterval);
|
||||
if (weaken(hook_malloc) || weaken(hook_calloc) || weaken(hook_realloc) ||
|
||||
weaken(hook_realloc_in_place) || weaken(hook_pvalloc) ||
|
||||
|
|
|
@ -4,27 +4,49 @@
|
|||
|
||||
#define kAsanScale 3
|
||||
#define kAsanMagic 0x7fff8000
|
||||
#define kAsanHeapFree -1
|
||||
#define kAsanStackFree -2
|
||||
#define kAsanRelocated -3
|
||||
#define kAsanHeapUnderrun -4
|
||||
#define kAsanHeapOverrun -5
|
||||
#define kAsanGlobalOverrun -6
|
||||
#define kAsanGlobalUnregistered -7
|
||||
#define kAsanStackUnderrun -8
|
||||
#define kAsanStackOverrun -9
|
||||
#define kAsanAllocaUnderrun -10
|
||||
#define kAsanAllocaOverrun -11
|
||||
#define kAsanUnscoped -12
|
||||
#define kAsanUnmapped -13
|
||||
#define kAsanHeapFree -1 /* F */
|
||||
#define kAsanStackFree -2 /* F */
|
||||
#define kAsanRelocated -3 /* R */
|
||||
#define kAsanHeapUnderrun -4 /* U */
|
||||
#define kAsanHeapOverrun -5 /* O */
|
||||
#define kAsanGlobalOverrun -6 /* O */
|
||||
#define kAsanGlobalUnregistered -7 /* G */
|
||||
#define kAsanStackUnderrun -8 /* U */
|
||||
#define kAsanStackOverrun -9 /* O */
|
||||
#define kAsanAllocaUnderrun -10 /* U */
|
||||
#define kAsanAllocaOverrun -11 /* O */
|
||||
#define kAsanUnscoped -12 /* S */
|
||||
#define kAsanUnmapped -13 /* M */
|
||||
#define kAsanProtected -14 /* P */
|
||||
#define kAsanStackGuard -15 /* _ */
|
||||
|
||||
#define SHADOW(x) ((signed char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic))
|
||||
#define SHADOW(x) ((signed char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic))
|
||||
#define UNSHADOW(x) ((void *)(((uintptr_t)(x) + 0x7fff8000) << 3))
|
||||
|
||||
struct AsanFault {
|
||||
char kind;
|
||||
signed char *shadow;
|
||||
};
|
||||
|
||||
void __asan_unpoison(uintptr_t, size_t);
|
||||
void __asan_verify(const void *, size_t);
|
||||
void __asan_map_shadow(uintptr_t, size_t);
|
||||
void __asan_poison(uintptr_t, size_t, int);
|
||||
void __asan_unpoison(uintptr_t, size_t);
|
||||
bool __asan_is_valid(const void *, size_t);
|
||||
bool __asan_is_valid_iov(const struct iovec *, int);
|
||||
bool __asan_is_valid_strlist(char *const *);
|
||||
bool __asan_is_valid_iov(const struct iovec *, int);
|
||||
struct AsanFault __asan_check(const void *, size_t);
|
||||
void __asan_report_memory_fault(void *, int, const char *) wontreturn;
|
||||
void __asan_report(void *, int, const char *, char) wontreturn;
|
||||
void *__asan_memalign(size_t, size_t);
|
||||
void __asan_free(void *);
|
||||
void *__asan_malloc(size_t);
|
||||
void *__asan_calloc(size_t, size_t);
|
||||
void *__asan_realloc(void *, size_t);
|
||||
void *__asan_realloc_in_place(void *, size_t);
|
||||
void *__asan_valloc(size_t);
|
||||
void *__asan_pvalloc(size_t);
|
||||
int __asan_malloc_trim(size_t);
|
||||
void __asan_die(const char *) wontreturn;
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */
|
||||
|
|
157
libc/intrin/bzero.c
Normal file
157
libc/intrin/bzero.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*-*- 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 2021 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/dce.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
static noinline antiquity void bzero_sse(char *p, size_t n) {
|
||||
xmm_t v = {0};
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
} else {
|
||||
do {
|
||||
n -= 32;
|
||||
*(xmm_t *)(p + n) = v;
|
||||
*(xmm_t *)(p + n + 16) = v;
|
||||
} while (n > 32);
|
||||
*(xmm_t *)(p + 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
}
|
||||
}
|
||||
|
||||
microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
|
||||
xmm_t v = {0};
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
} else if (!IsAsan() && n >= 1024 && X86_HAVE(ERMS)) {
|
||||
asm("rep stosb" : "+D"(p), "+c"(n), "=m"(*(char(*)[n])p) : "a"(0));
|
||||
} else {
|
||||
if (n < kHalfCache3 || !kHalfCache3) {
|
||||
do {
|
||||
n -= 32;
|
||||
*(xmm_t *)(p + n) = v;
|
||||
*(xmm_t *)(p + n + 16) = v;
|
||||
} while (n > 32);
|
||||
} else {
|
||||
while ((uintptr_t)(p + n) & 15) {
|
||||
p[--n] = 0;
|
||||
}
|
||||
do {
|
||||
n -= 32;
|
||||
__builtin_ia32_movntdq((xmm_a *)(p + n), (xmm_a)v);
|
||||
__builtin_ia32_movntdq((xmm_a *)(p + n + 16), (xmm_a)v);
|
||||
} while (n > 32);
|
||||
asm("sfence");
|
||||
}
|
||||
*(xmm_t *)(p + 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets memory to zero.
|
||||
*
|
||||
* bzero n=0 661 picoseconds
|
||||
* bzero n=1 661 ps/byte 1,476 mb/s
|
||||
* bzero n=2 330 ps/byte 2,952 mb/s
|
||||
* bzero n=3 220 ps/byte 4,428 mb/s
|
||||
* bzero n=4 165 ps/byte 5,904 mb/s
|
||||
* bzero n=7 94 ps/byte 10,333 mb/s
|
||||
* bzero n=8 41 ps/byte 23,618 mb/s
|
||||
* bzero n=15 44 ps/byte 22,142 mb/s
|
||||
* bzero n=16 20 ps/byte 47,236 mb/s
|
||||
* bzero n=31 21 ps/byte 45,760 mb/s
|
||||
* bzero n=32 20 ps/byte 47,236 mb/s
|
||||
* bzero n=63 10 ps/byte 92,997 mb/s
|
||||
* bzero n=64 15 ps/byte 62,982 mb/s
|
||||
* bzero n=127 15 ps/byte 62,490 mb/s
|
||||
* bzero n=128 10 ps/byte 94,473 mb/s
|
||||
* bzero n=255 14 ps/byte 68,439 mb/s
|
||||
* bzero n=256 9 ps/byte 105 gb/s
|
||||
* bzero n=511 15 ps/byte 62,859 mb/s
|
||||
* bzero n=512 11 ps/byte 83,976 mb/s
|
||||
* bzero n=1023 15 ps/byte 61,636 mb/s
|
||||
* bzero n=1024 10 ps/byte 88,916 mb/s
|
||||
* bzero n=2047 9 ps/byte 105 gb/s
|
||||
* bzero n=2048 8 ps/byte 109 gb/s
|
||||
* bzero n=4095 8 ps/byte 115 gb/s
|
||||
* bzero n=4096 8 ps/byte 118 gb/s
|
||||
* bzero n=8191 7 ps/byte 129 gb/s
|
||||
* bzero n=8192 7 ps/byte 130 gb/s
|
||||
* bzero n=16383 6 ps/byte 136 gb/s
|
||||
* bzero n=16384 6 ps/byte 137 gb/s
|
||||
* bzero n=32767 6 ps/byte 140 gb/s
|
||||
* bzero n=32768 6 ps/byte 141 gb/s
|
||||
* bzero n=65535 15 ps/byte 64,257 mb/s
|
||||
* bzero n=65536 15 ps/byte 64,279 mb/s
|
||||
* bzero n=131071 15 ps/byte 63,166 mb/s
|
||||
* bzero n=131072 15 ps/byte 63,115 mb/s
|
||||
* bzero n=262143 15 ps/byte 62,052 mb/s
|
||||
* bzero n=262144 15 ps/byte 62,097 mb/s
|
||||
* bzero n=524287 15 ps/byte 61,699 mb/s
|
||||
* bzero n=524288 15 ps/byte 61,674 mb/s
|
||||
* bzero n=1048575 16 ps/byte 60,179 mb/s
|
||||
* bzero n=1048576 15 ps/byte 61,330 mb/s
|
||||
* bzero n=2097151 15 ps/byte 61,071 mb/s
|
||||
* bzero n=2097152 15 ps/byte 61,065 mb/s
|
||||
* bzero n=4194303 16 ps/byte 60,942 mb/s
|
||||
* bzero n=4194304 16 ps/byte 60,947 mb/s
|
||||
* bzero n=8388607 16 ps/byte 60,872 mb/s
|
||||
* bzero n=8388608 16 ps/byte 60,879 mb/s
|
||||
*
|
||||
* @param p is memory address
|
||||
* @param n is byte length
|
||||
* @return p
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
void(bzero)(void *p, size_t n) {
|
||||
char *b;
|
||||
uint64_t x;
|
||||
b = p;
|
||||
if (IsTiny()) {
|
||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
|
||||
return;
|
||||
}
|
||||
asm("xorl\t%k0,%k0" : "=r"(x));
|
||||
if (n <= 16) {
|
||||
if (n >= 8) {
|
||||
__builtin_memcpy(b, &x, 8);
|
||||
__builtin_memcpy(b + n - 8, &x, 8);
|
||||
} else if (n >= 4) {
|
||||
__builtin_memcpy(b, &x, 4);
|
||||
__builtin_memcpy(b + n - 4, &x, 4);
|
||||
} else if (n) {
|
||||
do {
|
||||
asm volatile("" ::: "memory");
|
||||
b[--n] = x;
|
||||
} while (n);
|
||||
}
|
||||
} else if (X86_HAVE(AVX)) {
|
||||
bzero_avx(b, n);
|
||||
} else {
|
||||
bzero_sse(b, n);
|
||||
}
|
||||
}
|
21
libc/intrin/fatalbuf.c
Normal file
21
libc/intrin/fatalbuf.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*-*- 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 2021 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/log/libfatal.internal.h"
|
||||
|
||||
char __fatalbuf[FRAMESIZE];
|
1
libc/intrin/ho.s
Normal file
1
libc/intrin/ho.s
Normal file
|
@ -0,0 +1 @@
|
|||
bsr %rdi,%rax
|
|
@ -46,8 +46,27 @@ o/$(MODE)/libc/intrin/ubsan.o: \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-fno-sanitize=all \
|
||||
-fno-stack-protector \
|
||||
-mgeneral-regs-only \
|
||||
-O2
|
||||
-O3
|
||||
|
||||
o/$(MODE)/libc/intrin/memcmp.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-Os
|
||||
|
||||
o//libc/intrin/memmove.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-fno-toplevel-reorder
|
||||
|
||||
o//libc/intrin/bzero.o \
|
||||
o//libc/intrin/memset.o \
|
||||
o//libc/intrin/memmove.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O3
|
||||
|
||||
o/tiny/libc/intrin/memcmp.o \
|
||||
o/tiny/libc/intrin/memmove.o \
|
||||
o/tiny/libc/intrin/memmove-gcc.asm: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-fpie
|
||||
|
||||
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
|
||||
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
|
||||
|
|
210
libc/intrin/memcmp.c
Normal file
210
libc/intrin/memcmp.c
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
|
||||
static noinline antiquity int memcmp_sse(const unsigned char *p,
|
||||
const unsigned char *q, size_t n) {
|
||||
uint64_t w;
|
||||
unsigned u, u0, u1, u2, u3;
|
||||
if (n > 32) {
|
||||
while (n > 16 + 16) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)p, *(const xmm_t *)q)) -
|
||||
0xffff)) {
|
||||
n -= 16;
|
||||
p += 16;
|
||||
q += 16;
|
||||
} else {
|
||||
u = __builtin_ctzl(u);
|
||||
return p[u] - q[u];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)p, *(const xmm_t *)q)) -
|
||||
0xffff)) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)(p + n - 16), *(const xmm_t *)(q + n - 16))) -
|
||||
0xffff)) {
|
||||
return 0;
|
||||
} else {
|
||||
u = __builtin_ctzl(u);
|
||||
return p[n - 16 + u] - q[n - 16 + u];
|
||||
}
|
||||
} else {
|
||||
u = __builtin_ctzl(u);
|
||||
return p[u] - q[u];
|
||||
}
|
||||
}
|
||||
|
||||
microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
||||
const unsigned char *q,
|
||||
size_t n) {
|
||||
uint64_t w;
|
||||
unsigned u, u0, u1, u2, u3;
|
||||
if (n > 32) {
|
||||
while (n >= 16 + 64) {
|
||||
u0 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
((const xmm_t *)p)[0], ((const xmm_t *)q)[0]));
|
||||
u1 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
((const xmm_t *)p)[1], ((const xmm_t *)q)[1]));
|
||||
u2 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
((const xmm_t *)p)[2], ((const xmm_t *)q)[2]));
|
||||
u3 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
((const xmm_t *)p)[3], ((const xmm_t *)q)[3]));
|
||||
w = (uint64_t)u0 | (uint64_t)u1 << 16 | (uint64_t)u2 << 32 |
|
||||
(uint64_t)u3 << 48;
|
||||
if (w == -1) {
|
||||
n -= 64;
|
||||
p += 64;
|
||||
q += 64;
|
||||
} else {
|
||||
w = __builtin_ctzll(w ^ -1);
|
||||
return p[w] - q[w];
|
||||
}
|
||||
}
|
||||
while (n > 16 + 16) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)p, *(const xmm_t *)q)) -
|
||||
0xffff)) {
|
||||
n -= 16;
|
||||
p += 16;
|
||||
q += 16;
|
||||
} else {
|
||||
u = __builtin_ctzl(u);
|
||||
return p[u] - q[u];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)p, *(const xmm_t *)q)) -
|
||||
0xffff)) {
|
||||
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
|
||||
*(const xmm_t *)(p + n - 16), *(const xmm_t *)(q + n - 16))) -
|
||||
0xffff)) {
|
||||
return 0;
|
||||
} else {
|
||||
u = __builtin_ctzl(u);
|
||||
return p[n - 16 + u] - q[n - 16 + u];
|
||||
}
|
||||
} else {
|
||||
u = __builtin_ctzl(u);
|
||||
return p[u] - q[u];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares memory byte by byte.
|
||||
*
|
||||
* memcmp n=0 992 picoseconds
|
||||
* memcmp n=1 1 ns/byte 738 mb/s
|
||||
* memcmp n=2 661 ps/byte 1,476 mb/s
|
||||
* memcmp n=3 551 ps/byte 1,771 mb/s
|
||||
* memcmp n=4 248 ps/byte 3,936 mb/s
|
||||
* memcmp n=5 198 ps/byte 4,920 mb/s
|
||||
* memcmp n=6 165 ps/byte 5,904 mb/s
|
||||
* memcmp n=7 141 ps/byte 6,889 mb/s
|
||||
* memcmp n=8 124 ps/byte 7,873 mb/s
|
||||
* memcmp n=9 110 ps/byte 8,857 mb/s
|
||||
* memcmp n=15 44 ps/byte 22,143 mb/s
|
||||
* memcmp n=16 41 ps/byte 23,619 mb/s
|
||||
* memcmp n=17 77 ps/byte 12,547 mb/s
|
||||
* memcmp n=31 42 ps/byte 22,881 mb/s
|
||||
* memcmp n=32 41 ps/byte 23,619 mb/s
|
||||
* memcmp n=33 60 ps/byte 16,238 mb/s
|
||||
* memcmp n=80 53 ps/byte 18,169 mb/s
|
||||
* memcmp n=128 38 ps/byte 25,194 mb/s
|
||||
* memcmp n=256 32 ps/byte 30,233 mb/s
|
||||
* memcmp n=16384 27 ps/byte 35,885 mb/s
|
||||
* memcmp n=32768 29 ps/byte 32,851 mb/s
|
||||
* memcmp n=131072 33 ps/byte 28,983 mb/s
|
||||
*
|
||||
* @return unsigned char subtraction at stop index
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int memcmp(const void *a, const void *b, size_t n) {
|
||||
int c;
|
||||
unsigned u;
|
||||
uint32_t k, i, j;
|
||||
uint64_t w, x, y;
|
||||
const unsigned char *p, *q;
|
||||
if ((p = a) == (q = b)) return 0;
|
||||
if (!IsTiny()) {
|
||||
if (n <= 16) {
|
||||
if (n >= 8) {
|
||||
if (!(w = (x = ((uint64_t)p[0] << 000 | (uint64_t)p[1] << 010 |
|
||||
(uint64_t)p[2] << 020 | (uint64_t)p[3] << 030 |
|
||||
(uint64_t)p[4] << 040 | (uint64_t)p[5] << 050 |
|
||||
(uint64_t)p[6] << 060 | (uint64_t)p[7] << 070)) ^
|
||||
(y = ((uint64_t)q[0] << 000 | (uint64_t)q[1] << 010 |
|
||||
(uint64_t)q[2] << 020 | (uint64_t)q[3] << 030 |
|
||||
(uint64_t)q[4] << 040 | (uint64_t)q[5] << 050 |
|
||||
(uint64_t)q[6] << 060 | (uint64_t)q[7] << 070)))) {
|
||||
p += n - 8;
|
||||
q += n - 8;
|
||||
if (!(w = (x = ((uint64_t)p[0] << 000 | (uint64_t)p[1] << 010 |
|
||||
(uint64_t)p[2] << 020 | (uint64_t)p[3] << 030 |
|
||||
(uint64_t)p[4] << 040 | (uint64_t)p[5] << 050 |
|
||||
(uint64_t)p[6] << 060 | (uint64_t)p[7] << 070)) ^
|
||||
(y = ((uint64_t)q[0] << 000 | (uint64_t)q[1] << 010 |
|
||||
(uint64_t)q[2] << 020 | (uint64_t)q[3] << 030 |
|
||||
(uint64_t)q[4] << 040 | (uint64_t)q[5] << 050 |
|
||||
(uint64_t)q[6] << 060 | (uint64_t)q[7] << 070)))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
u = __builtin_ctzll(w);
|
||||
u = u & -8;
|
||||
return ((x >> u) & 255) - ((y >> u) & 255);
|
||||
} else if (n >= 4) {
|
||||
if (!(k = (i = ((uint32_t)p[0] << 000 | (uint32_t)p[1] << 010 |
|
||||
(uint32_t)p[2] << 020 | (uint32_t)p[3] << 030)) ^
|
||||
(j = ((uint32_t)q[0] << 000 | (uint32_t)q[1] << 010 |
|
||||
(uint32_t)q[2] << 020 | (uint32_t)q[3] << 030)))) {
|
||||
p += n - 4;
|
||||
q += n - 4;
|
||||
if (!(k = (i = ((uint32_t)p[0] << 000 | (uint32_t)p[1] << 010 |
|
||||
(uint32_t)p[2] << 020 | (uint32_t)p[3] << 030)) ^
|
||||
(j = ((uint32_t)q[0] << 000 | (uint32_t)q[1] << 010 |
|
||||
(uint32_t)q[2] << 020 | (uint32_t)q[3] << 030)))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
u = __builtin_ctzl(k);
|
||||
u = u & -8;
|
||||
return ((i >> u) & 255) - ((j >> u) & 255);
|
||||
}
|
||||
} else if (LIKELY(X86_HAVE(AVX))) {
|
||||
return memcmp_avx(p, q, n);
|
||||
} else {
|
||||
return memcmp_sse(p, q, n);
|
||||
}
|
||||
}
|
||||
for (; n; ++p, ++q, --n) {
|
||||
if ((c = *p - *q)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
309
libc/intrin/memmove.c
Normal file
309
libc/intrin/memmove.c
Normal file
|
@ -0,0 +1,309 @@
|
|||
/*-*- 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 2021 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/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
asm("memcpy = memmove\n\t"
|
||||
".globl\tmemcpy");
|
||||
|
||||
/**
|
||||
* Copies memory.
|
||||
*
|
||||
* memmove n=0 661 picoseconds
|
||||
* memmove n=1 661 ps/byte 1,476 mb/s
|
||||
* memmove n=2 330 ps/byte 2,952 mb/s
|
||||
* memmove n=3 330 ps/byte 2,952 mb/s
|
||||
* memmove n=4 165 ps/byte 5,904 mb/s
|
||||
* memmove n=7 141 ps/byte 6,888 mb/s
|
||||
* memmove n=8 82 ps/byte 11 GB/s
|
||||
* memmove n=15 44 ps/byte 21 GB/s
|
||||
* memmove n=16 41 ps/byte 23 GB/s
|
||||
* memmove n=31 32 ps/byte 29 GB/s
|
||||
* memmove n=32 31 ps/byte 30 GB/s
|
||||
* memmove n=63 21 ps/byte 45 GB/s
|
||||
* memmove n=64 15 ps/byte 61 GB/s
|
||||
* memmove n=127 13 ps/byte 73 GB/s
|
||||
* memmove n=128 31 ps/byte 30 GB/s
|
||||
* memmove n=255 20 ps/byte 45 GB/s
|
||||
* memmove n=256 19 ps/byte 49 GB/s
|
||||
* memmove n=511 16 ps/byte 56 GB/s
|
||||
* memmove n=512 17 ps/byte 54 GB/s
|
||||
* memmove n=1023 18 ps/byte 52 GB/s
|
||||
* memmove n=1024 13 ps/byte 72 GB/s
|
||||
* memmove n=2047 9 ps/byte 96 GB/s
|
||||
* memmove n=2048 9 ps/byte 98 GB/s
|
||||
* memmove n=4095 8 ps/byte 112 GB/s
|
||||
* memmove n=4096 8 ps/byte 109 GB/s
|
||||
* memmove n=8191 7 ps/byte 124 GB/s
|
||||
* memmove n=8192 7 ps/byte 125 GB/s
|
||||
* memmove n=16383 7 ps/byte 134 GB/s
|
||||
* memmove n=16384 7 ps/byte 134 GB/s
|
||||
* memmove n=32767 13 ps/byte 72 GB/s
|
||||
* memmove n=32768 13 ps/byte 72 GB/s
|
||||
* memmove n=65535 13 ps/byte 68 GB/s
|
||||
* memmove n=65536 14 ps/byte 67 GB/s
|
||||
* memmove n=131071 14 ps/byte 65 GB/s
|
||||
* memmove n=131072 14 ps/byte 64 GB/s
|
||||
* memmove n=262143 15 ps/byte 63 GB/s
|
||||
* memmove n=262144 15 ps/byte 63 GB/s
|
||||
* memmove n=524287 15 ps/byte 61 GB/s
|
||||
* memmove n=524288 15 ps/byte 61 GB/s
|
||||
* memmove n=1048575 15 ps/byte 61 GB/s
|
||||
* memmove n=1048576 15 ps/byte 61 GB/s
|
||||
* memmove n=2097151 19 ps/byte 48 GB/s
|
||||
* memmove n=2097152 27 ps/byte 35 GB/s
|
||||
* memmove n=4194303 28 ps/byte 33 GB/s
|
||||
* memmove n=4194304 28 ps/byte 33 GB/s
|
||||
* memmove n=8388607 28 ps/byte 33 GB/s
|
||||
* memmove n=8388608 28 ps/byte 33 GB/s
|
||||
*
|
||||
* DST and SRC may overlap.
|
||||
*
|
||||
* @param dst is destination
|
||||
* @param src is memory to copy
|
||||
* @param n is number of bytes to copy
|
||||
* @return dst
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
void *memmove(void *dst, const void *src, size_t n) {
|
||||
size_t i;
|
||||
char *d, *r;
|
||||
const char *s;
|
||||
uint64_t a, b;
|
||||
xmm_t v, w, x, y, V, W, X, Y, wut;
|
||||
d = dst;
|
||||
s = src;
|
||||
if (IsTiny()) {
|
||||
if (d <= s) {
|
||||
asm("rep movsb"
|
||||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
|
||||
: "m"(*(char(*)[n])src));
|
||||
} else {
|
||||
d += n - 1;
|
||||
s += n - 1;
|
||||
asm("std\n\t"
|
||||
"rep movsb\n\t"
|
||||
"cld"
|
||||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
|
||||
: "m"(*(char(*)[n])src));
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
switch (n) {
|
||||
case 0:
|
||||
return d;
|
||||
case 1:
|
||||
*d = *s;
|
||||
return d;
|
||||
case 2:
|
||||
__builtin_memcpy(&a, s, 2);
|
||||
__builtin_memcpy(d, &a, 2);
|
||||
return d;
|
||||
case 3:
|
||||
__builtin_memcpy(&a, s, 2);
|
||||
__builtin_memcpy(&b, s + 1, 2);
|
||||
__builtin_memcpy(d, &a, 2);
|
||||
__builtin_memcpy(d + 1, &b, 2);
|
||||
return d;
|
||||
case 4:
|
||||
__builtin_memcpy(&a, s, 4);
|
||||
__builtin_memcpy(d, &a, 4);
|
||||
return d;
|
||||
case 5 ... 7:
|
||||
__builtin_memcpy(&a, s, 4);
|
||||
__builtin_memcpy(&b, s + n - 4, 4);
|
||||
__builtin_memcpy(d, &a, 4);
|
||||
__builtin_memcpy(d + n - 4, &b, 4);
|
||||
return d;
|
||||
case 8:
|
||||
__builtin_memcpy(&a, s, 8);
|
||||
__builtin_memcpy(d, &a, 8);
|
||||
return d;
|
||||
case 9 ... 15:
|
||||
__builtin_memcpy(&a, s, 8);
|
||||
__builtin_memcpy(&b, s + n - 8, 8);
|
||||
__builtin_memcpy(d, &a, 8);
|
||||
__builtin_memcpy(d + n - 8, &b, 8);
|
||||
return d;
|
||||
case 16:
|
||||
*(xmm_t *)d = *(xmm_t *)s;
|
||||
return d;
|
||||
case 17 ... 32:
|
||||
v = *(xmm_t *)s;
|
||||
w = *(xmm_t *)(s + n - 16);
|
||||
*(xmm_t *)d = v;
|
||||
*(xmm_t *)(d + n - 16) = w;
|
||||
return d;
|
||||
case 33 ... 64:
|
||||
v = *(xmm_t *)s;
|
||||
w = *(xmm_t *)(s + 16);
|
||||
x = *(xmm_t *)(s + n - 32);
|
||||
y = *(xmm_t *)(s + n - 16);
|
||||
*(xmm_t *)d = v;
|
||||
*(xmm_t *)(d + 16) = w;
|
||||
*(xmm_t *)(d + n - 32) = x;
|
||||
*(xmm_t *)(d + n - 16) = y;
|
||||
return d;
|
||||
case 65 ... 127:
|
||||
v = *(xmm_t *)s;
|
||||
w = *(xmm_t *)(s + 16);
|
||||
x = *(xmm_t *)(s + 32);
|
||||
y = *(xmm_t *)(s + 48);
|
||||
V = *(xmm_t *)(s + n - 64);
|
||||
W = *(xmm_t *)(s + n - 48);
|
||||
X = *(xmm_t *)(s + n - 32);
|
||||
Y = *(xmm_t *)(s + n - 16);
|
||||
*(xmm_t *)d = v;
|
||||
*(xmm_t *)(d + 16) = w;
|
||||
*(xmm_t *)(d + 32) = x;
|
||||
*(xmm_t *)(d + 48) = y;
|
||||
*(xmm_t *)(d + n - 64) = V;
|
||||
*(xmm_t *)(d + n - 48) = W;
|
||||
*(xmm_t *)(d + n - 32) = X;
|
||||
*(xmm_t *)(d + n - 16) = Y;
|
||||
return d;
|
||||
default:
|
||||
r = d;
|
||||
if (d == s) return d;
|
||||
if (n < kHalfCache3 || !kHalfCache3) {
|
||||
if (d > s) {
|
||||
if (IsAsan() || n < 1024 || !X86_HAVE(ERMS)) {
|
||||
do {
|
||||
n -= 32;
|
||||
v = *(const xmm_t *)(s + n);
|
||||
w = *(const xmm_t *)(s + n + 16);
|
||||
*(xmm_t *)(d + n) = v;
|
||||
*(xmm_t *)(d + n + 16) = w;
|
||||
} while (n >= 32);
|
||||
} else {
|
||||
asm("std\n\t"
|
||||
"rep movsb\n\t"
|
||||
"cld"
|
||||
: "=D"(d), "=S"(s), "+c"(n), "=m"(*(char(*)[n])d)
|
||||
: "0"(d + n - 1), "1"(s + n - 1), "m"(*(char(*)[n])s));
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
if (IsAsan() || n < 1024 || !X86_HAVE(ERMS)) {
|
||||
i = 0;
|
||||
do {
|
||||
v = *(const xmm_t *)(s + i);
|
||||
w = *(const xmm_t *)(s + i + 16);
|
||||
*(xmm_t *)(d + i) = v;
|
||||
*(xmm_t *)(d + i + 16) = w;
|
||||
} while ((i += 32) + 32 <= n);
|
||||
d += i;
|
||||
s += i;
|
||||
n -= i;
|
||||
} else {
|
||||
asm("rep movsb"
|
||||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
|
||||
: "m"(*(char(*)[n])s));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (d > s) {
|
||||
while ((uintptr_t)(d + n) & 15) {
|
||||
--n;
|
||||
d[n] = s[n];
|
||||
}
|
||||
do {
|
||||
n -= 32;
|
||||
v = *(const xmm_t *)(s + n);
|
||||
w = *(const xmm_t *)(s + n + 16);
|
||||
__builtin_ia32_movntdq((xmm_a *)(d + n), v);
|
||||
__builtin_ia32_movntdq((xmm_a *)(d + n + 16), w);
|
||||
} while (n >= 32);
|
||||
} else {
|
||||
i = 0;
|
||||
while ((uintptr_t)(d + i) & 15) {
|
||||
d[i] = s[i];
|
||||
++i;
|
||||
}
|
||||
do {
|
||||
v = *(const xmm_t *)(s + i);
|
||||
w = *(const xmm_t *)(s + i + 16);
|
||||
__builtin_ia32_movntdq((xmm_a *)(d + i), v);
|
||||
__builtin_ia32_movntdq((xmm_a *)(d + i + 16), w);
|
||||
} while ((i += 32) + 32 <= n);
|
||||
d += i;
|
||||
s += i;
|
||||
n -= i;
|
||||
}
|
||||
asm("sfence");
|
||||
}
|
||||
switch (n) {
|
||||
case 0:
|
||||
return r;
|
||||
case 17 ... 31:
|
||||
__builtin_memcpy(&v, s, 16);
|
||||
__builtin_memcpy(&w, s + n - 16, 16);
|
||||
__builtin_memcpy(d, &v, 16);
|
||||
__builtin_memcpy(d + n - 16, &w, 16);
|
||||
return r;
|
||||
case 9 ... 15:
|
||||
__builtin_memcpy(&a, s, 8);
|
||||
__builtin_memcpy(&b, s + n - 8, 8);
|
||||
__builtin_memcpy(d, &a, 8);
|
||||
__builtin_memcpy(d + n - 8, &b, 8);
|
||||
return r;
|
||||
case 5 ... 7:
|
||||
__builtin_memcpy(&a, s, 4);
|
||||
__builtin_memcpy(&b, s + n - 4, 4);
|
||||
__builtin_memcpy(d, &a, 4);
|
||||
__builtin_memcpy(d + n - 4, &b, 4);
|
||||
return r;
|
||||
case 16:
|
||||
__builtin_memcpy(&v, s, 16);
|
||||
__builtin_memcpy(d, &v, 16);
|
||||
return r;
|
||||
case 8:
|
||||
__builtin_memcpy(&a, s, 8);
|
||||
__builtin_memcpy(d, &a, 8);
|
||||
return r;
|
||||
case 4:
|
||||
__builtin_memcpy(&a, s, 4);
|
||||
__builtin_memcpy(d, &a, 4);
|
||||
return r;
|
||||
case 1:
|
||||
*d = *s;
|
||||
return r;
|
||||
case 2:
|
||||
__builtin_memcpy(&a, s, 2);
|
||||
__builtin_memcpy(d, &a, 2);
|
||||
return r;
|
||||
case 3:
|
||||
__builtin_memcpy(&a, s, 2);
|
||||
__builtin_memcpy(&b, s + 1, 2);
|
||||
__builtin_memcpy(d, &a, 2);
|
||||
__builtin_memcpy(d + 1, &b, 2);
|
||||
return r;
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
|
||||
void *mempcpy_pure(void *dst, const void *src, size_t n) {
|
||||
memmove_pure(dst, src, n);
|
||||
void *mempcpy(void *dst, const void *src, size_t n) {
|
||||
memmove(dst, src, n);
|
||||
return (char *)dst + n;
|
||||
}
|
164
libc/intrin/memset.c
Normal file
164
libc/intrin/memset.c
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*-*- 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 2021 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/dce.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
static noinline antiquity void *memset_sse(char *p, char c, size_t n) {
|
||||
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
} else {
|
||||
do {
|
||||
n -= 32;
|
||||
*(xmm_t *)(p + n) = v;
|
||||
*(xmm_t *)(p + n + 16) = v;
|
||||
} while (n > 32);
|
||||
*(xmm_t *)(p + 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
microarchitecture("avx") static void *memset_avx(char *p, char c, size_t n) {
|
||||
char *t;
|
||||
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||
if (n <= 32) {
|
||||
*(xmm_t *)(p + n - 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
} else if (!IsAsan() && n >= 1024 && X86_HAVE(ERMS)) {
|
||||
asm("rep stosb" : "=D"(t), "+c"(n), "=m"(*(char(*)[n])p) : "0"(p), "a"(c));
|
||||
} else {
|
||||
if (n < kHalfCache3 || !kHalfCache3) {
|
||||
do {
|
||||
n -= 32;
|
||||
*(xmm_t *)(p + n) = v;
|
||||
*(xmm_t *)(p + n + 16) = v;
|
||||
} while (n > 32);
|
||||
} else {
|
||||
while ((uintptr_t)(p + n) & 15) {
|
||||
p[--n] = c;
|
||||
}
|
||||
do {
|
||||
n -= 32;
|
||||
__builtin_ia32_movntdq((xmm_a *)(p + n), (xmm_a)v);
|
||||
__builtin_ia32_movntdq((xmm_a *)(p + n + 16), (xmm_a)v);
|
||||
} while (n > 32);
|
||||
asm("sfence");
|
||||
}
|
||||
*(xmm_t *)(p + 16) = v;
|
||||
*(xmm_t *)p = v;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets memory.
|
||||
*
|
||||
* memset n=0 992 picoseconds
|
||||
* memset n=1 992 ps/byte 984 mb/s
|
||||
* memset n=2 330 ps/byte 2,952 mb/s
|
||||
* memset n=3 330 ps/byte 2,952 mb/s
|
||||
* memset n=4 165 ps/byte 5,904 mb/s
|
||||
* memset n=7 94 ps/byte 10,333 mb/s
|
||||
* memset n=8 124 ps/byte 7,872 mb/s
|
||||
* memset n=15 66 ps/byte 14,761 mb/s
|
||||
* memset n=16 62 ps/byte 15,745 mb/s
|
||||
* memset n=31 32 ps/byte 30,506 mb/s
|
||||
* memset n=32 20 ps/byte 47,236 mb/s
|
||||
* memset n=63 26 ps/byte 37,198 mb/s
|
||||
* memset n=64 20 ps/byte 47,236 mb/s
|
||||
* memset n=127 23 ps/byte 41,660 mb/s
|
||||
* memset n=128 12 ps/byte 75,578 mb/s
|
||||
* memset n=255 18 ps/byte 53,773 mb/s
|
||||
* memset n=256 12 ps/byte 75,578 mb/s
|
||||
* memset n=511 17 ps/byte 55,874 mb/s
|
||||
* memset n=512 12 ps/byte 75,578 mb/s
|
||||
* memset n=1023 16 ps/byte 58,080 mb/s
|
||||
* memset n=1024 11 ps/byte 86,375 mb/s
|
||||
* memset n=2047 9 ps/byte 101 gb/s
|
||||
* memset n=2048 8 ps/byte 107 gb/s
|
||||
* memset n=4095 8 ps/byte 113 gb/s
|
||||
* memset n=4096 8 ps/byte 114 gb/s
|
||||
* memset n=8191 7 ps/byte 126 gb/s
|
||||
* memset n=8192 7 ps/byte 126 gb/s
|
||||
* memset n=16383 7 ps/byte 133 gb/s
|
||||
* memset n=16384 7 ps/byte 131 gb/s
|
||||
* memset n=32767 14 ps/byte 69,246 mb/s
|
||||
* memset n=32768 6 ps/byte 138 gb/s
|
||||
* memset n=65535 15 ps/byte 62,756 mb/s
|
||||
* memset n=65536 15 ps/byte 62,982 mb/s
|
||||
* memset n=131071 18 ps/byte 52,834 mb/s
|
||||
* memset n=131072 15 ps/byte 62,023 mb/s
|
||||
* memset n=262143 15 ps/byte 61,169 mb/s
|
||||
* memset n=262144 16 ps/byte 61,011 mb/s
|
||||
* memset n=524287 16 ps/byte 60,633 mb/s
|
||||
* memset n=524288 16 ps/byte 57,902 mb/s
|
||||
* memset n=1048575 16 ps/byte 60,405 mb/s
|
||||
* memset n=1048576 16 ps/byte 58,754 mb/s
|
||||
* memset n=2097151 16 ps/byte 59,329 mb/s
|
||||
* memset n=2097152 16 ps/byte 58,729 mb/s
|
||||
* memset n=4194303 16 ps/byte 59,329 mb/s
|
||||
* memset n=4194304 16 ps/byte 59,262 mb/s
|
||||
* memset n=8388607 16 ps/byte 59,530 mb/s
|
||||
* memset n=8388608 16 ps/byte 60,205 mb/s
|
||||
*
|
||||
* @param p is memory address
|
||||
* @param c is masked with 255 and used as repeated byte
|
||||
* @param n is byte length
|
||||
* @return p
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
void *memset(void *p, int c, size_t n) {
|
||||
char *b;
|
||||
uint32_t u;
|
||||
uint64_t x;
|
||||
b = p;
|
||||
if (IsTiny()) {
|
||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
|
||||
return p;
|
||||
}
|
||||
if (n <= 16) {
|
||||
if (n >= 8) {
|
||||
x = 0x0101010101010101ul * (c & 255);
|
||||
__builtin_memcpy(b, &x, 8);
|
||||
__builtin_memcpy(b + n - 8, &x, 8);
|
||||
} else if (n >= 4) {
|
||||
u = 0x01010101u * (c & 255);
|
||||
__builtin_memcpy(b, &u, 4);
|
||||
__builtin_memcpy(b + n - 4, &u, 4);
|
||||
} else if (n) {
|
||||
do {
|
||||
asm volatile("" ::: "memory");
|
||||
b[--n] = c;
|
||||
} while (n);
|
||||
}
|
||||
return b;
|
||||
} else if (X86_HAVE(AVX)) {
|
||||
return memset_avx(b, c, n);
|
||||
} else {
|
||||
return memset_sse(b, c, n);
|
||||
}
|
||||
}
|
185
libc/intrin/printf.c
Normal file
185
libc/intrin/printf.c
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*-*- 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 2021 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/log/libfatal.internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
/**
|
||||
* Low-level printf.
|
||||
*
|
||||
* This will work without any cosmopolitan runtime support once the
|
||||
* executable has been loaded into memory.
|
||||
*/
|
||||
privileged noasan noinstrument void __printf(const char *fmt, ...) {
|
||||
long d, ax;
|
||||
va_list va;
|
||||
uint16_t dx;
|
||||
const char *s;
|
||||
uint32_t wrote;
|
||||
unsigned long x;
|
||||
unsigned char al;
|
||||
const char16_t *S;
|
||||
int n, t, w, plus;
|
||||
char c, f, *p, *e, b[2048];
|
||||
w = 0;
|
||||
p = b;
|
||||
e = p + sizeof(b);
|
||||
va_start(va, fmt);
|
||||
do {
|
||||
switch ((c = *fmt++)) {
|
||||
default:
|
||||
if (p < e) {
|
||||
*p++ = c;
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
case '%':
|
||||
w = 0;
|
||||
f = ' ';
|
||||
plus = 0;
|
||||
NeedMoar:
|
||||
switch ((c = *fmt++)) {
|
||||
case '\0':
|
||||
break;
|
||||
case '0':
|
||||
f = c;
|
||||
goto NeedMoar;
|
||||
case '+':
|
||||
plus = c;
|
||||
goto NeedMoar;
|
||||
case '*':
|
||||
w = va_arg(va, int);
|
||||
goto NeedMoar;
|
||||
case 'd':
|
||||
d = va_arg(va, long);
|
||||
ApiAbuse:
|
||||
if (p + 22 <= e) {
|
||||
if (d || !plus) {
|
||||
if (d > 0 && plus) {
|
||||
*p++ = plus;
|
||||
}
|
||||
p = __intcpy(p, d);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
w = 12;
|
||||
f = '0';
|
||||
/* fallthrough */
|
||||
case 'x':
|
||||
x = va_arg(va, unsigned long);
|
||||
if (x) {
|
||||
n = __builtin_clzl(x) ^ (sizeof(long) * 8 - 1);
|
||||
n >>= 2;
|
||||
n += 1;
|
||||
} else {
|
||||
n = 1;
|
||||
}
|
||||
while (w-- > n) {
|
||||
if (p < e) {
|
||||
*p++ = f;
|
||||
}
|
||||
}
|
||||
while (n--) {
|
||||
if (p < e) {
|
||||
*p++ = "0123456789abcdef"[(x >> (n << 2)) & 15];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
s = va_arg(va, const char *);
|
||||
if (!s) {
|
||||
EmitNullString:
|
||||
s = "NULL";
|
||||
}
|
||||
if ((uintptr_t)s < PAGESIZE) {
|
||||
d = (intptr_t)s;
|
||||
goto ApiAbuse;
|
||||
}
|
||||
for (n = 0; s[n];) ++n;
|
||||
while (w-- > n) {
|
||||
if (p < e) {
|
||||
*p++ = f;
|
||||
}
|
||||
}
|
||||
while ((t = *s++)) {
|
||||
if (p < e) {
|
||||
*p++ = t;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
S = va_arg(va, const char16_t *);
|
||||
if (!S) goto EmitNullString;
|
||||
while ((t = *S++)) {
|
||||
if (p + 3 <= e && (t & 0xfc00) != 0xdc00) {
|
||||
if (t <= 0x7ff) {
|
||||
p[0] = 0300 | t >> 6;
|
||||
p[1] = 0200 | x << 8 | t & 077;
|
||||
p += 2;
|
||||
} else {
|
||||
if (t > 0xffff) t = 0xfffd;
|
||||
p[0] = 0340 | t >> 12;
|
||||
p[1] = 0200 | x << 8 | (t >> 6) & 077;
|
||||
p[2] = 0200 | x << 8 | t & 077;
|
||||
p += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (c);
|
||||
va_end(va);
|
||||
if (p == e) {
|
||||
e[-4] = '.';
|
||||
e[-3] = '.';
|
||||
e[-2] = '.';
|
||||
e[-1] = '\n';
|
||||
}
|
||||
if (IsWindows()) {
|
||||
WriteFile(GetStdHandle(kNtStdErrorHandle), b, p - b, &wrote, 0);
|
||||
} else if (IsMetal()) {
|
||||
for (e = p, p = b; p < e; ++p) {
|
||||
for (;;) {
|
||||
dx = 0x3F8 + UART_LSR;
|
||||
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
|
||||
if (al & UART_TTYTXR) break;
|
||||
asm("pause");
|
||||
}
|
||||
dx = 0x3F8;
|
||||
asm volatile("outb\t%0,%1"
|
||||
: /* no inputs */
|
||||
: "a"(*p), "dN"(dx));
|
||||
}
|
||||
} else {
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_write), "D"(2), "S"(b), "d"(p - b)
|
||||
: "rcx", "r11", "memory");
|
||||
}
|
||||
}
|
43
libc/intrin/strlen.c
Normal file
43
libc/intrin/strlen.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- 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 2021 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/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
/**
|
||||
* Returns length of NUL-terminated string.
|
||||
*
|
||||
* @param s is non-null NUL-terminated string pointer
|
||||
* @return number of bytes (excluding NUL)
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
noasan size_t strlen(const char *s) {
|
||||
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);
|
||||
if (IsAsan()) __asan_verify(s, 1);
|
||||
m = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(*p, z)) >> k << k;
|
||||
while (!m) m = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(*++p, z));
|
||||
n = (const char *)p + __builtin_ctzl(m) - s;
|
||||
if (IsAsan()) __asan_verify(s, n);
|
||||
return n;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 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 │
|
||||
|
@ -18,10 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
// Returns arc sine of 𝑥.
|
||||
//
|
||||
// @param 𝑥 is double scalar in low half of %xmm0
|
||||
// @return double scalar in low half of %xmm0
|
||||
asin: ezlea asinl,ax
|
||||
jmp _d2ld2
|
||||
.endfn asin,globl
|
||||
__syscall__:
|
||||
syscall
|
||||
ret
|
||||
.endfn __syscall__,globl,hidden
|
|
@ -18,6 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/log.h"
|
||||
|
||||
const char *GetAddr2linePath(void) {
|
||||
noasan const char *GetAddr2linePath(void) {
|
||||
return commandvenv("ADDR2LINE", "addr2line");
|
||||
}
|
||||
|
|
|
@ -17,65 +17,107 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/clktck.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
|
||||
static void AppendInt(char **b, int64_t x) {
|
||||
char buf[27], *e;
|
||||
e = FormatInt64Thousands(buf, x);
|
||||
appendd(b, buf, e - buf);
|
||||
}
|
||||
|
||||
static void AppendMetric(char **b, const char *s1, int64_t x, const char *s2,
|
||||
const char *nl) {
|
||||
appends(b, s1);
|
||||
AppendInt(b, x);
|
||||
appends(b, s2);
|
||||
appends(b, nl);
|
||||
}
|
||||
|
||||
static void AppendUnit(char **b, int64_t x, const char *s) {
|
||||
AppendInt(b, x);
|
||||
appendw(b, ' ');
|
||||
appends(b, s);
|
||||
if (x == 1) {
|
||||
appendw(b, 's');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates process resource usage report.
|
||||
*/
|
||||
void AppendResourceReport(char **b, struct rusage *ru, const char *nl) {
|
||||
char ibuf[27];
|
||||
long utime, stime;
|
||||
long double ticks;
|
||||
if (ru->ru_maxrss) {
|
||||
(appendf)(b, "ballooned to %,ldkb in size%s", ru->ru_maxrss, nl);
|
||||
AppendMetric(b, "ballooned to ", ru->ru_maxrss, "kb in size", nl);
|
||||
}
|
||||
if ((utime = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec) |
|
||||
(stime = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec)) {
|
||||
appends(b, "needed ");
|
||||
AppendInt(b, utime + stime);
|
||||
appends(b, "us cpu (");
|
||||
AppendInt(b, (long double)stime / (utime + stime) * 100);
|
||||
appends(b, "% kernel)");
|
||||
appends(b, nl);
|
||||
ticks = ceill((long double)(utime + stime) / (1000000.L / CLK_TCK));
|
||||
(appendf)(b, "needed %,ldµs cpu (%d%% kernel)%s", utime + stime,
|
||||
(int)((long double)stime / (utime + stime) * 100), nl);
|
||||
if (ru->ru_idrss) {
|
||||
(appendf)(b, "needed %,ldkb memory on average%s",
|
||||
lroundl(ru->ru_idrss / ticks), nl);
|
||||
AppendMetric(b, "needed ", lroundl(ru->ru_idrss / ticks),
|
||||
" memory on average", nl);
|
||||
}
|
||||
if (ru->ru_isrss) {
|
||||
(appendf)(b, "needed %,ldkb stack on average%s",
|
||||
lroundl(ru->ru_isrss / ticks), nl);
|
||||
AppendMetric(b, "needed ", lroundl(ru->ru_isrss / ticks),
|
||||
" stack on average", nl);
|
||||
}
|
||||
if (ru->ru_ixrss) {
|
||||
(appendf)(b, "mapped %,ldkb shared on average%s",
|
||||
lroundl(ru->ru_ixrss / ticks), nl);
|
||||
AppendMetric(b, "needed ", lroundl(ru->ru_ixrss / ticks),
|
||||
" shared on average", nl);
|
||||
}
|
||||
}
|
||||
if (ru->ru_minflt || ru->ru_majflt) {
|
||||
(appendf)(b, "caused %,ld page faults (%d%% memcpy)%s",
|
||||
ru->ru_minflt + ru->ru_majflt,
|
||||
(int)((long double)ru->ru_minflt /
|
||||
(ru->ru_minflt + ru->ru_majflt) * 100),
|
||||
nl);
|
||||
appends(b, "caused ");
|
||||
AppendInt(b, ru->ru_minflt + ru->ru_majflt);
|
||||
appends(b, " page faults (");
|
||||
AppendInt(
|
||||
b, (long double)ru->ru_minflt / (ru->ru_minflt + ru->ru_majflt) * 100);
|
||||
appends(b, "% memcpy)");
|
||||
appends(b, nl);
|
||||
}
|
||||
if (ru->ru_nvcsw + ru->ru_nivcsw > 1) {
|
||||
(appendf)(
|
||||
b, "%,ld context switches (%d%% consensual)%s",
|
||||
ru->ru_nvcsw + ru->ru_nivcsw,
|
||||
(int)((long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100),
|
||||
nl);
|
||||
AppendInt(b, ru->ru_nvcsw + ru->ru_nivcsw);
|
||||
appends(b, " context switch (");
|
||||
AppendInt(b,
|
||||
(long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100);
|
||||
appends(b, "% consensual)");
|
||||
appends(b, nl);
|
||||
}
|
||||
if (ru->ru_msgrcv || ru->ru_msgsnd) {
|
||||
(appendf)(b, "received %,ld message%s and sent %,ld%s", ru->ru_msgrcv,
|
||||
ru->ru_msgrcv == 1 ? "" : "s", ru->ru_msgsnd, nl);
|
||||
appends(b, "received ");
|
||||
AppendUnit(b, ru->ru_msgrcv, "message");
|
||||
appends(b, " and sent ");
|
||||
AppendInt(b, ru->ru_msgsnd);
|
||||
appends(b, nl);
|
||||
}
|
||||
if (ru->ru_inblock || ru->ru_oublock) {
|
||||
(appendf)(b, "performed %,ld read%s and %,ld write i/o operations%s",
|
||||
ru->ru_inblock, ru->ru_inblock == 1 ? "" : "s", ru->ru_oublock,
|
||||
nl);
|
||||
appends(b, "performed ");
|
||||
AppendUnit(b, ru->ru_inblock, "read");
|
||||
appends(b, " and ");
|
||||
AppendInt(b, ru->ru_oublock);
|
||||
appends(b, " write i/o operations");
|
||||
appends(b, nl);
|
||||
}
|
||||
if (ru->ru_nsignals) {
|
||||
(appendf)(b, "received %,ld signals%s", ru->ru_nsignals, nl);
|
||||
appends(b, "received ");
|
||||
AppendUnit(b, ru->ru_nsignals, "signal");
|
||||
appends(b, nl);
|
||||
}
|
||||
if (ru->ru_nswap) {
|
||||
(appendf)(b, "got swapped %,ld times%s", ru->ru_nswap, nl);
|
||||
appends(b, "got swapped ");
|
||||
AppendUnit(b, ru->ru_nswap, "time");
|
||||
appends(b, nl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,12 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -40,7 +42,8 @@
|
|||
#define kBacktraceMaxFrames 128
|
||||
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
|
||||
|
||||
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||
static noasan int PrintBacktraceUsingAddr2line(int fd,
|
||||
const struct StackFrame *bp) {
|
||||
ssize_t got;
|
||||
intptr_t addr;
|
||||
size_t i, j, gi;
|
||||
|
@ -52,9 +55,8 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
||||
if (IsOpenbsd()) return -1;
|
||||
if (IsWindows()) return -1;
|
||||
if (!(debugbin = FindDebugBinary()) || !(addr2line = GetAddr2linePath())) {
|
||||
return -1;
|
||||
}
|
||||
if (!(debugbin = FindDebugBinary())) return -1;
|
||||
if (!(addr2line = GetAddr2linePath())) return -1;
|
||||
i = 0;
|
||||
j = 0;
|
||||
argv[i++] = "addr2line";
|
||||
|
@ -132,11 +134,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(fd, p1, p2 - p1);
|
||||
__write(p1, p2 - p1);
|
||||
got -= p3 - p1;
|
||||
p1 += p3 - p1;
|
||||
} else {
|
||||
write(fd, p1, got);
|
||||
__write(p1, got);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +156,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
}
|
||||
}
|
||||
|
||||
static int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
||||
static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
||||
if (!IsTiny()) {
|
||||
if (PrintBacktraceUsingAddr2line(fd, bp) != -1) {
|
||||
return 0;
|
||||
|
@ -163,7 +165,7 @@ static int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
|||
return PrintBacktraceUsingSymbols(fd, bp, GetSymbolTable());
|
||||
}
|
||||
|
||||
void ShowBacktrace(int fd, const struct StackFrame *bp) {
|
||||
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
|
||||
static bool noreentry;
|
||||
++ftrace;
|
||||
if (!bp) bp = __builtin_frame_address(0);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/gc.internal.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
|
@ -40,52 +41,42 @@
|
|||
* @param st is open symbol table for current executable
|
||||
* @return -1 w/ errno if error happened
|
||||
*/
|
||||
int PrintBacktraceUsingSymbols(int fd, const struct StackFrame *bp,
|
||||
struct SymbolTable *st) {
|
||||
int rc;
|
||||
char *p;
|
||||
noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
|
||||
const struct StackFrame *bp,
|
||||
struct SymbolTable *st) {
|
||||
size_t gi;
|
||||
intptr_t addr;
|
||||
int64_t addend;
|
||||
int symbol, addend;
|
||||
struct Garbages *garbage;
|
||||
char buf[256], ibuf[21];
|
||||
const struct Symbol *symbol;
|
||||
const struct StackFrame *frame;
|
||||
++ftrace;
|
||||
if (!bp) bp = __builtin_frame_address(0);
|
||||
garbage = weaken(__garbage);
|
||||
gi = garbage ? garbage->i : 0;
|
||||
for (rc = 0, frame = bp; frame; frame = frame->next) {
|
||||
for (frame = bp; frame; frame = frame->next) {
|
||||
addr = frame->addr;
|
||||
if (addr == weakaddr("__gc")) {
|
||||
do {
|
||||
--gi;
|
||||
} while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
|
||||
}
|
||||
p = buf;
|
||||
p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)frame, ibuf, 48));
|
||||
*p++ = ' ';
|
||||
p = mempcpy(p, ibuf, uint64toarray_fixed16(addr, ibuf, 48));
|
||||
*p++ = ' ';
|
||||
if (st && st->count &&
|
||||
((intptr_t)addr >= (intptr_t)&_base &&
|
||||
(intptr_t)addr <= (intptr_t)&_end)) {
|
||||
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
|
||||
st->count, addr - st->addr_base - 1)];
|
||||
p = stpcpy(p, &st->name_base[symbol->name_rva]);
|
||||
addend = addr - st->addr_base - symbol->addr_rva;
|
||||
*p++ = addend >= 0 ? '+' : '-';
|
||||
if (addend) *p++ = '0', *p++ = 'x';
|
||||
p = mempcpy(p, ibuf, uint64toarray_radix16(ABS(addend), ibuf));
|
||||
/*
|
||||
* we subtract one to handle the case of noreturn functions with a
|
||||
* call instruction at the end, since %rip in such cases will point
|
||||
* to the start of the next function. generally %rip always points
|
||||
* to the byte after the instruction. one exception is in case like
|
||||
* __restore_rt where the kernel creates a stack frame that points
|
||||
* to the beginning of the function.
|
||||
*/
|
||||
if ((symbol = GetSymbol(st, addr - 1)) != -1 ||
|
||||
(symbol = GetSymbol(st, addr - 0)) != -1) {
|
||||
addend = addr - st->addr_base;
|
||||
addend -= st->symbols[symbol].x;
|
||||
} else {
|
||||
p = stpcpy(p, "UNKNOWN");
|
||||
}
|
||||
*p++ = '\n';
|
||||
if (write(fd, buf, p - buf) == -1) {
|
||||
rc = -1;
|
||||
break;
|
||||
addend = 0;
|
||||
}
|
||||
__printf("%p %p %s%+d\r\n", frame, addr, GetSymbolName(st, symbol), addend);
|
||||
}
|
||||
--ftrace;
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
bool cancolor(void) {
|
||||
static bool once;
|
||||
static bool result;
|
||||
return 1;
|
||||
if (!once) {
|
||||
result = (!IsWindows() || NtGetVersion() >= kNtVersionWindows10 ||
|
||||
!ischardev(1)) &&
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue