Make improvements

- Fix build flakes
- Polyfill SIGWINCH on Windows
- Fix an execve issue on Windows
- Make strerror show more information
- Improve cmd.exe setup/teardown on Windows
- Support bracketed paste mode in Blinkenlights
- Show keyboard shortcuts in Blinkenlights status bar
- Fixed copy_file_range() and copyfile() w/ zip filesystem
- Size optimize GetDosArgv() to keep life.com 12kb in size
- Improve Blinkenlights ability to load weird ELF executables
- Fix program_executable_name and add GetInterpreterExecutableName
- Make Python in tiny mode fail better if docstrings are requested
- Update Python test exclusions in tiny* modes such as tinylinux
- Add bulletproof unbreakable kprintf() troubleshooting function
- Remove "oldskool" keyword from ape.S for virus scanners
- Fix issue that caused backtraces to not print sometimes
- Improve Blinkenlights serial uart character i/o
- Make clock_gettime() not clobber errno on xnu
- Improve sha256 cpuid check for old computers
- Integrate some bestline linenoise fixes
- Show runit process names better in htop
- Remove SIGPIPE from ShowCrashReports()
- Make realpath() not clobber errno
- Avoid attaching GDB on non-Linux
- Improve img.com example
This commit is contained in:
Justine Tunney 2022-03-16 13:33:13 -07:00
parent 2a938b3eaa
commit b45d50b690
194 changed files with 4881 additions and 2966 deletions

View file

@ -1,42 +0,0 @@
/*-*- 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/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
/**
* Handles failure of assert() macro.
*/
relegated wontreturn void __assert_fail(const char *expr, const char *file,
int line) {
static bool noreentry;
__printf("%s:%d: assert(%s) failed\r\n", file, line, expr);
if (cmpxchg(&noreentry, false, true)) {
if (weaken(__die)) {
weaken(__die)();
} else {
__printf("can't backtrace b/c `__die` not linked\r\n");
}
quick_exit(23);
}
_Exit(24);
}

View file

@ -16,13 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/pushpop.h"
#include "libc/bits/weaken.h"
#include "libc/dce.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/pedef.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
@ -38,18 +32,8 @@
* @noreturn
*/
wontreturn void exit(int exitcode) {
const uintptr_t *p;
if (weaken(__cxa_finalize)) {
weaken(__cxa_finalize)(NULL);
}
for (p = __fini_array_end; p > __fini_array_start;) {
((void (*)(void))(*--p))();
}
if (SupportsWindows() && __ntconsolemode) {
SetConsoleMode(GetStdHandle(pushpop(kNtStdInputHandle)), __ntconsolemode);
SetConsoleMode(GetStdHandle(pushpop(kNtStdOutputHandle)),
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing);
}
_Exit(exitcode);
quick_exit(exitcode);
}

View file

@ -17,9 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/nt/process.h"
extern int __pid;
/**
* Creates new process.
@ -29,7 +34,7 @@
*/
int fork(void) {
axdx_t ad;
int ax, dx;
int ax, dx, parent;
if (!IsWindows()) {
ad = sys_fork();
ax = ad.ax;
@ -43,7 +48,19 @@ int fork(void) {
ax = sys_fork_nt();
}
if (!ax) {
__onfork();
if (!IsWindows()) {
dx = sys_getpid().ax;
} else {
dx = GetCurrentProcessId();
}
parent = __pid;
__pid = dx;
SYSDEBUG("fork() → 0 (child of %d)", parent);
if (weaken(__onfork)) {
weaken(__onfork)();
}
} else {
SYSDEBUG("fork() → %d% m", ax);
}
return ax;
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
@ -91,9 +92,9 @@ privileged noinstrument noasan noubsan void ftracer(void) {
if ((symbol = __get_symbol(g_symbols, frame->addr)) != -1 &&
symbol != g_lastsymbol) {
g_lastsymbol = symbol;
__printf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "",
__get_symbol_name(g_symbols, symbol),
(long)(unsignedsubtract(stamp, laststamp) / 3.3));
kprintf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "",
__get_symbol_name(g_symbols, symbol),
(long)(unsignedsubtract(stamp, laststamp) / 3.3));
laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
}
}
@ -110,9 +111,9 @@ textstartup void ftrace_install(void) {
ftrace_enabled = 1;
__hook(ftrace_hook, g_symbols);
} else {
__printf("error: --ftrace failed to open symbol table\r\n");
kprintf("error: --ftrace failed to open symbol table\r\n");
}
} else {
__printf("error: --ftrace needs concomitant .com.dbg binary\r\n");
kprintf("error: --ftrace needs concomitant .com.dbg binary\r\n");
}
}

View file

@ -16,9 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/str/str.h"
@ -32,25 +30,23 @@ struct DosArgv {
wint_t wc;
};
static textwindows noasan wint_t DecodeDosArgv(const char16_t **s) {
textwindows noasan void DecodeDosArgv(int ignore, struct DosArgv *st) {
wint_t x, y;
for (;;) {
if (!(x = *(*s)++)) break;
if (IsUtf16Cont(x)) continue;
if (IsUcs2(x)) {
return x;
} else {
if ((y = *(*s)++)) {
return MergeUtf16(x, y);
if (!(x = *st->s++)) break;
if (!IsUcs2(x)) {
if ((y = *st->s++)) {
x = MergeUtf16(x, y);
} else {
return 0;
x = 0;
}
}
break;
}
return x;
st->wc = x;
}
static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
static textwindows noasan void AppendDosArgv(wint_t wc, struct DosArgv *st) {
uint64_t w;
w = tpenc(wc);
do {
@ -59,6 +55,16 @@ static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
} while (w >>= 8);
}
static textwindows noasan int Count(int c, struct DosArgv *st) {
int ignore, n = 0;
asm("" : "=g"(ignore));
while (st->wc == c) {
DecodeDosArgv(ignore, st);
n++;
}
return n;
}
/**
* Tokenizes and transcodes Windows NT CLI args, thus avoiding
* CommandLineToArgv() schlepping in forty megs of dependencies.
@ -81,49 +87,60 @@ static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf,
size_t size, char **argv, size_t max) {
bool inquote;
size_t i, argc, slashes, quotes;
struct DosArgv st;
st.s = cmdline;
st.p = buf;
st.pe = buf + size;
int i, argc, slashes, quotes, ignore;
static struct DosArgv st_;
struct DosArgv *st = &st_;
asm("" : "=g"(ignore));
asm("" : "+r"(st));
st->s = cmdline;
st->p = buf;
st->pe = buf + size;
argc = 0;
st.wc = DecodeDosArgv(&st.s);
while (st.wc) {
while (st.wc && (st.wc == ' ' || st.wc == '\t')) {
st.wc = DecodeDosArgv(&st.s);
DecodeDosArgv(ignore, st);
while (st->wc) {
while (st->wc && (st->wc == ' ' || st->wc == '\t')) {
DecodeDosArgv(ignore, st);
}
if (!st.wc) break;
if (!st->wc) break;
if (++argc < max) {
argv[argc - 1] = st.p < st.pe ? st.p : NULL;
argv[argc - 1] = st->p < st->pe ? st->p : NULL;
}
inquote = false;
while (st.wc) {
if (!inquote && (st.wc == ' ' || st.wc == '\t')) break;
if (st.wc == '"' || st.wc == '\\') {
slashes = 0;
quotes = 0;
while (st.wc == '\\') st.wc = DecodeDosArgv(&st.s), slashes++;
while (st.wc == '"') st.wc = DecodeDosArgv(&st.s), quotes++;
while (st->wc) {
if (!inquote && (st->wc == ' ' || st->wc == '\t')) break;
if (st->wc == '"' || st->wc == '\\') {
slashes = Count('\\', st);
quotes = Count('"', st);
if (!quotes) {
while (slashes--) AppendDosArgv(&st, '\\');
while (slashes--) {
AppendDosArgv('\\', st);
}
} else {
while (slashes >= 2) AppendDosArgv(&st, '\\'), slashes -= 2;
if (slashes) AppendDosArgv(&st, '"'), quotes--;
while (slashes >= 2) {
AppendDosArgv('\\', st);
slashes -= 2;
}
if (slashes) {
AppendDosArgv('"', st);
quotes--;
}
if (quotes > 0) {
if (!inquote) quotes--;
for (i = 3; i <= quotes + 1; i += 3) AppendDosArgv(&st, '"');
for (i = 3; i <= quotes + 1; i += 3) {
AppendDosArgv('"', st);
}
inquote = (quotes % 3 == 0);
}
}
} else {
AppendDosArgv(&st, st.wc);
st.wc = DecodeDosArgv(&st.s);
AppendDosArgv(st->wc, st);
DecodeDosArgv(ignore, st);
}
}
AppendDosArgv(&st, '\0');
AppendDosArgv('\0', st);
}
AppendDosArgv(&st, '\0');
if (size) buf[min(st.p - buf, size - 1)] = '\0';
AppendDosArgv('\0', st);
if (size) buf[min(st->p - buf, size - 1)] = '\0';
if (max) argv[min(argc, max - 1)] = NULL;
return argc;
}

View file

@ -32,7 +32,6 @@ static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
wint_t x, y;
for (v = r.ax = 0, r.dx = 0;;) {
if (!(x = src[r.dx++])) break;
if (IsUtf16Cont(x)) continue;
if (!IsUcs2(x)) {
y = src[r.dx++];
x = MergeUtf16(x, y);

View file

@ -16,34 +16,68 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/pushpop.h"
#include "libc/bits/weaken.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Exits process faster.
* Returns path of executable interperter.
*
* @param exitcode is masked with 255
* @noreturn
* Unlike `program_executable_name` which is designed to figure out the
* absolute path of the first argument passed to `execve()`, what we do
* here is probe things like `/proc` and `sysctl()` to figure out if we
* were launched by something like `ape-loader`, and then we return its
* path. If we can't determine that path, possibly because we're on XNU
* or OpenBSD, then we return -1 with an error code.
*
* @param p receives utf8 output
* @param n is byte size of res buffer
* @return p on success or null w/ errno if out of buf or error
* @see program_invocation_short_name
* @see program_invocation_name
* @see program_executable_name
*/
wontreturn void quick_exit(int exitcode) {
const uintptr_t *p;
if (weaken(fflush)) {
weaken(fflush)(0);
char *GetInterpreterExecutableName(char *p, size_t n) {
int e;
size_t m;
int cmd[4];
ssize_t rc;
char *r, *t;
e = errno;
if (n < 2) {
errno = ENAMETOOLONG;
} else if (IsWindows()) {
if (strlen(program_executable_name) < n) {
strcpy(p, program_executable_name);
return p;
}
errno = ENAMETOOLONG;
} else if ((rc = sys_readlinkat(AT_FDCWD, "/proc/self/exe", p, n - 1)) > 0) {
p[rc] = 0;
return p;
} else if ((rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, n - 1)) >
0) {
errno = e;
p[n] = 0;
return p;
} else if (IsFreebsd() || IsNetbsd()) {
cmd[0] = 1 /* CTL_KERN */;
cmd[1] = 14 /* KERN_PROC */;
if (IsFreebsd()) {
cmd[2] = 12 /* KERN_PROC_PATHNAME */;
} else {
cmd[2] = 5 /* KERN_PROC_PATHNAME */;
}
cmd[3] = -1; /* current process */
if (sysctl(cmd, ARRAYLEN(cmd), p, &n, 0, 0) != -1) {
errno = e;
return p;
}
}
for (p = __fini_array_end; p > __fini_array_start;) {
((void (*)(void))(*--p))();
}
if (SupportsWindows() && __ntconsolemode) {
SetConsoleMode(GetStdHandle(pushpop(kNtStdInputHandle)), __ntconsolemode);
SetConsoleMode(GetStdHandle(pushpop(kNtStdOutputHandle)),
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing);
}
_Exit(exitcode);
return 0;
}

View file

@ -12,7 +12,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern uint32_t __ntconsolemode;
extern uint32_t __ntconsolemode[2];
extern const char v_ntsubsystem[] __attribute__((__weak__));
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
extern const uintptr_t __fini_array_start[] __attribute__((__weak__));

View file

@ -21,8 +21,9 @@ COSMOPOLITAN_C_START_
#define kFixedmapStart _kMem(0x300000000000, 0x000040000000)
#define kFixedmapSize \
_kMem(0x400000000000 - 0x300000000000, 0x000070000000 - 0x000040000000)
#define _kMmi(VSPACE) \
ROUNDUP(VSPACE / FRAMESIZE * sizeof(struct MemoryInterval), FRAMESIZE)
#define _kMmi(VSPACE) \
ROUNDUP(VSPACE / FRAMESIZE * (intptr_t)sizeof(struct MemoryInterval), \
FRAMESIZE)
#define _kMem(NORMAL, WIN7) \
(!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7)
@ -35,7 +36,7 @@ struct MemoryInterval {
};
struct MemoryIntervals {
long i, n;
size_t i, n;
struct MemoryInterval *p;
struct MemoryInterval s[OPEN_MAX];
};
@ -57,6 +58,10 @@ int UntrackMemoryIntervals(void *, size_t) hidden;
#define IsLegalPointer(p) \
(-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff)
forceinline pureconst bool IsLegalSize(size_t n) {
return n <= 0xffffffffffff;
}
forceinline pureconst bool IsAutoFrame(int x) {
return (kAutomapStart >> 16) <= x &&
x <= ((kAutomapStart + (kAutomapSize - 1)) >> 16);
@ -75,14 +80,26 @@ forceinline pureconst bool IsShadowFrame(int x) {
return 0x7fff <= x && x < 0x10008000;
}
forceinline pureconst bool IsKernelFrame(int x) {
return (int)(GetStaticStackAddr(0) >> 16) <= x &&
x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >>
16);
}
forceinline pureconst bool IsStaticStackFrame(int x) {
return (GetStaticStackAddr(0) >> 16) <= x &&
x <= ((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16);
return (int)(GetStaticStackAddr(0) >> 16) <= x &&
x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >>
16);
}
forceinline pureconst bool IsStackFrame(int x) {
return (int)(GetStackAddr(0) >> 16) <= x &&
x <= (int)((GetStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsSigAltStackFrame(int x) {
return (GetStackAddr(0) >> 16) <= x &&
x <= ((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16);
return (int)(GetStackAddr(0) >> 16) <= x &&
x <= (int)((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsOldStackFrame(int x) {

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/itoa.h"
#include "libc/log/libfatal.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/runtime/memtrack.internal.h"
@ -41,20 +41,20 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
for (i = 0; i < mm->i; ++i) {
frames = mm->p[i].y + 1 - mm->p[i].x;
maptally += frames;
__printf("%012x-%012x %s %,*dx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1),
DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
DescribeFrame(mm->p[i].x));
kprintf("%012lx-%012lx %s %'*ldx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1),
DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
DescribeFrame(mm->p[i].x));
if (i + 1 < _mmi.i) {
frames = mm->p[i + 1].x - mm->p[i].y - 1;
if (frames && IsNoteworthyHole(i, mm)) {
gaptally += frames;
__printf(" w/ %,d frame hole", frames);
kprintf(" w/ %'ld frame hole", frames);
}
}
if (mm->p[i].h != -1) {
__printf(" h=%d", mm->p[i].h);
kprintf(" h=%ld", mm->p[i].h);
}
__printf("\r\n");
kprintf("%n");
}
__printf("# %d frames mapped w/ %,d frames gapped\r\n", maptally, gaptally);
kprintf("# %ld frames mapped w/ %'ld frames gapped%n", maptally, gaptally);
}

View file

@ -1,135 +0,0 @@
/*-*- 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/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/prot.h"
#define SIZE 1024
#define CTL_KERN 1
#define KERN_PROC 14
#define KERN_PROC_PATHNAME_FREEBSD 12
#define KERN_PROC_PATHNAME_NETBSD 5
/**
* Absolute path of executable.
*
* This variable is initialized automatically at startup. The path is
* guaranteed to exist, except on XNU and OpenBSD. It may be a symlink.
* It may be spoofed.
*/
char program_executable_name[SIZE];
static textwindows bool GetNtExePath(char executable[SIZE]) {
uint64_t w;
wint_t x, y;
uint32_t i, j;
char16_t path16[PATH_MAX + 1];
if (!GetModuleFileName(0, path16, ARRAYLEN(path16))) return 0;
for (i = j = 0; (x = path16[i++] & 0xffff);) {
if (!IsUcs2(x)) {
y = path16[i++] & 0xffff;
x = MergeUtf16(x, y);
}
if (x == '\\') x = '/';
w = tpenc(x);
do {
executable[j] = w;
if (++j == SIZE) {
return false;
}
} while ((w >>= 8));
}
executable[j] = 0;
return true;
}
static textstartup void GetProgramExecutableName(char executable[SIZE],
char *p) {
char *t;
size_t m;
int cmd[4];
ssize_t n = 0;
if (IsWindows() && GetNtExePath(executable)) return;
if (fileexists(p)) {
if (!_isabspath(p)) {
if (getcwd(executable, SIZE - 1)) {
n = strlen(executable);
executable[n++] = '/';
}
}
} else if ((n = sys_readlinkat(AT_FDCWD, "/proc/self/exe", executable,
SIZE - 1)) > 0) {
executable[n] = 0;
return;
} else if ((n = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", executable,
SIZE - 1)) > 0) {
executable[n] = 0;
return;
} else if (IsFreebsd() || IsNetbsd()) {
cmd[0] = CTL_KERN;
cmd[1] = KERN_PROC;
if (IsFreebsd()) {
cmd[2] = KERN_PROC_PATHNAME_FREEBSD;
} else {
cmd[2] = KERN_PROC_PATHNAME_NETBSD;
}
cmd[3] = -1;
m = SIZE;
if (sysctl(cmd, ARRAYLEN(cmd), executable, &m, 0, 0) != -1) {
return;
}
}
if (n < 0) n = 0;
for (; *p; ++p) {
if (n + 1 < SIZE) {
executable[n++] = *p;
}
}
executable[n] = 0;
}
textstartup void program_executable_name_init(int argc, char **argv,
char **envp, intptr_t *auxv) {
static bool once;
char executable[SIZE];
if (!cmpxchg(&once, 0, 1)) return;
__stpcpy(program_executable_name, argv[0]);
GetProgramExecutableName(executable, argv[0]);
__stpcpy(program_executable_name, executable);
SYSDEBUG("GetProgramExecutableName() -> %s", program_executable_name);
}
const void *const program_executable_name_init_ctor[] initarray = {
program_executable_name_init,
};

View file

@ -97,6 +97,7 @@ int OpenExecutable(void);
void ftrace_install(void);
long GetResourceLimit(int);
long GetMaxFd(void);
char *GetInterpreterExecutableName(char *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_RUNTIME_STACK_H_
#include "ape/config.h"
#include "libc/dce.h"
#include "libc/nt/version.h"
#include "libc/runtime/runtime.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -27,7 +28,7 @@
/**
* Tunes APE stack virtual address.
*
* This defaults to `0x700000000000 - STACKSIZE`. The value defined by
* This defaults to `0x7e0000000000 - STACKSIZE`. The value defined by
* this macro will be respected, with two exceptions: (1) in MODE=tiny
* the operating system provided stack is used instead and (2) Windows
* Seven doesn't support 64-bit addresses so 0x10000000 - GetStackSize
@ -48,7 +49,7 @@
#define _STACK_EXTRA ""
#endif
#if defined(__GNUC__) && defined(__ELF__)
#if defined(__GNUC__) && defined(__ELF__) && !defined(__STRICT_ANSI__)
COSMOPOLITAN_C_START_
extern char ape_stack_memsz[] __attribute__((__weak__));
@ -64,18 +65,18 @@ extern char ape_stack_memsz[] __attribute__((__weak__));
/**
* Returns preferred bottom address of stack.
*/
#define GetStaticStackAddr(ADDEND) \
({ \
intptr_t vAddr; \
if (!IsWindows() || NtGetVersion() >= kNtVersionWindows10) { \
asm(".weak\tape_stack_vaddr\n\t" \
"movabs\t%1+ape_stack_vaddr,%0" \
: "=r"(vAddr) \
: "i"(ADDEND)); \
} else { \
vAddr = 0x10000000; \
} \
vAddr; \
#define GetStaticStackAddr(ADDEND) \
({ \
intptr_t vAddr; \
if (!IsWindows() || IsAtLeastWindows10()) { \
__asm__(".weak\tape_stack_vaddr\n\t" \
"movabs\t%1+ape_stack_vaddr,%0" \
: "=r"(vAddr) \
: "i"(ADDEND)); \
} else { \
vAddr = 0x10000000; \
} \
vAddr; \
})
COSMOPOLITAN_C_END_

View file

@ -22,9 +22,11 @@
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/filemapflags.h"
@ -66,9 +68,20 @@ struct WinArgs {
char envblock[ARG_MAX];
};
uint32_t __ntconsolemode;
extern int __pid;
extern bool __nomultics;
extern const char kConsoleHandles[2];
static noasan textwindows noinstrument void MakeLongDoubleLongAgain(void) {
static const short kConsoleModes[2] = {
kNtEnableProcessedInput | kNtEnableLineInput | kNtEnableEchoInput |
kNtEnableMouseInput | kNtEnableQuickEditMode | kNtEnableExtendedFlags |
kNtEnableAutoPosition | kNtEnableInsertMode |
kNtEnableVirtualTerminalInput,
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing,
};
forceinline void MakeLongDoubleLongAgain(void) {
/* 8087 FPU Control Word
IM: Invalid Operation
DM: Denormal Operand
@ -90,29 +103,22 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(void) {
int64_t h;
int version;
int i, count;
int64_t inhand;
int64_t hand;
struct WinArgs *wa;
const char16_t *env16;
intptr_t stackaddr, allocaddr;
size_t allocsize, argsize, stacksize;
extern char os asm("__hostos");
os = WINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */
version = NtGetPeb()->OSMajorVersion;
__oldstack = (intptr_t)__builtin_frame_address(0);
if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) {
SetConsoleCP(kNtCpUtf8);
SetConsoleOutputCP(kNtCpUtf8);
inhand = GetStdHandle(pushpop(kNtStdInputHandle));
SetEnvironmentVariable(u"TERM", u"xterm-truecolor");
GetConsoleMode(inhand, &__ntconsolemode);
SetConsoleMode(inhand, kNtEnableProcessedInput | kNtEnableLineInput |
kNtEnableEchoInput | kNtEnableMouseInput |
kNtEnableQuickEditMode | kNtEnableExtendedFlags |
kNtEnableAutoPosition |
kNtEnableVirtualTerminalInput);
SetConsoleMode(GetStdHandle(pushpop(kNtStdOutputHandle)),
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing);
for (i = 0; i < 2; ++i) {
hand = GetStdHandle(kConsoleHandles[i]);
GetConsoleMode(hand, __ntconsolemode + i);
SetConsoleMode(hand, kConsoleModes[i]);
}
}
_mmi.p = _mmi.s;
_mmi.n = ARRAYLEN(_mmi.s);
@ -186,6 +192,12 @@ noasan textwindows noinstrument int64_t WinMain(int64_t hInstance,
int64_t hPrevInstance,
const char *lpCmdLine,
int nCmdShow) {
extern char os asm("__hostos");
extern uint64_t ts asm("kStartTsc");
os = WINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */
ts = rdtsc();
__nomultics = true;
__pid = GetCurrentProcessId();
MakeLongDoubleLongAgain();
if (weaken(WinSockInit)) weaken(WinSockInit)();
if (weaken(WinMainForked)) weaken(WinMainForked)();