mirror of
				https://github.com/jart/cosmopolitan.git
				synced 2025-10-26 11:10:58 +00:00 
			
		
		
		
	Get Redbean fork() working on the New Technology
Now that we have understandable system call tracing on Windows, this change rewrites many of the polyfill internals for that platform, to help things get closer to tip top shape. Support for complex forking scenarios had been in a regressed state for quite some time. Now, it works! Subsequent changes should be able to address the performance.
This commit is contained in:
		
							parent
							
								
									efedef6e65
								
							
						
					
					
						commit
						0cb6b6ff4b
					
				
					 84 changed files with 1340 additions and 338 deletions
				
			
		
							
								
								
									
										21
									
								
								ape/ape.S
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								ape/ape.S
									
										
									
									
									
								
							|  | @ -1605,5 +1605,26 @@ ape_idata_ro: | |||
| __data_start: | ||||
| 	.previous | ||||
| 
 | ||||
| 	.section .dataepilogue,"aw",@progbits
 | ||||
| 	.type	__data_end,@object
 | ||||
| 	.globl	__data_end
 | ||||
| 	.hidden	__data_end
 | ||||
| __data_end: | ||||
| 	.previous | ||||
| 
 | ||||
| 	.section .bssprologue,"aw",@nobits
 | ||||
| 	.type	__bss_start,@object
 | ||||
| 	.globl	__bss_start
 | ||||
| 	.hidden	__bss_start
 | ||||
| __bss_start: | ||||
| 	.previous | ||||
| 
 | ||||
| 	.section .bssepilogue,"aw",@nobits
 | ||||
| 	.type	__bss_end,@object
 | ||||
| 	.globl	__bss_end
 | ||||
| 	.hidden	__bss_end
 | ||||
| __bss_end: | ||||
| 	.previous | ||||
| 
 | ||||
| .end | ||||
|  | ||||
|  | @ -358,6 +358,8 @@ SECTIONS { | |||
| 
 | ||||
|   .data . : { | ||||
| /*BEGIN: Read/Write Data */ | ||||
|     KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*))) | ||||
| /*BEGIN: NT FORK COPYING */ | ||||
|     KEEP(*(.dataprologue)) | ||||
|     *(.data .data.*) | ||||
|     KEEP(*(SORT_BY_NAME(.sort.data.*))) | ||||
|  | @ -378,6 +380,8 @@ SECTIONS { | |||
|     . = ALIGN(__SIZEOF_POINTER__); | ||||
|     KEEP(*(SORT_BY_NAME(.piro.data.sort.*))) | ||||
|     KEEP(*(.piro.pad.data)) | ||||
|     KEEP(*(.dataepilogue)) | ||||
| /*END: NT FORK COPYING */ | ||||
|     . = ALIGN(PAGESIZE); | ||||
|     HIDDEN(_edata = .); | ||||
|     PROVIDE_HIDDEN(edata = .); | ||||
|  | @ -404,6 +408,8 @@ SECTIONS { | |||
| /*BEGIN: bss memory that's addressable */ | ||||
| 
 | ||||
|   .bss ALIGN(64) : { | ||||
| /*BEGIN: NT FORK COPYING */ | ||||
|     KEEP(*(.bssprologue)) | ||||
|     KEEP(*(SORT_BY_NAME(.piro.bss.init.*))) | ||||
|     *(.piro.bss) | ||||
|     KEEP(*(SORT_BY_NAME(.piro.bss.sort.*))) | ||||
|  | @ -418,6 +424,8 @@ SECTIONS { | |||
| 
 | ||||
|     KEEP(*(SORT_BY_NAME(.sort.bss.*))) | ||||
| 
 | ||||
|     KEEP(*(.bssepilogue)) | ||||
| /*END: NT FORK COPYING */ | ||||
|     . = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */ | ||||
|     HIDDEN(_end = .); | ||||
|     PROVIDE_HIDDEN(end = .); | ||||
|  |  | |||
|  | @ -12,9 +12,12 @@ | |||
| #include "libc/log/log.h" | ||||
| #include "libc/nt/nt/process.h" | ||||
| #include "libc/rand/rand.h" | ||||
| #include "libc/runtime/gc.h" | ||||
| #include "libc/runtime/memtrack.internal.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/time/time.h" | ||||
| #include "libc/x/x.h" | ||||
| 
 | ||||
| dontinline void dostuff(const char *s) { | ||||
|   int i, us; | ||||
|  | @ -29,6 +32,8 @@ dontinline void dostuff(const char *s) { | |||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   int rc, child, wstatus; | ||||
|   /* puts(_gc(xiso8601ts(NULL))); */ | ||||
|   PrintMemoryIntervals(2, &_mmi); | ||||
|   CHECK_NE(-1, (child = fork())); | ||||
|   if (!child) { | ||||
|     /* child process */ | ||||
|  |  | |||
|  | @ -96,6 +96,7 @@ o//libc/calls/fcntl.o:					\ | |||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			-Os | ||||
| 
 | ||||
| # must use alloca()
 | ||||
| o/$(MODE)/libc/calls/execl.o				\ | ||||
| o/$(MODE)/libc/calls/execle.o				\ | ||||
| o/$(MODE)/libc/calls/execlp.o				\ | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ | |||
| #include "libc/nt/enum/filemapflags.h" | ||||
| #include "libc/nt/enum/pageflags.h" | ||||
| #include "libc/nt/memory.h" | ||||
| #include "libc/nt/process.h" | ||||
| #include "libc/nt/runtime.h" | ||||
| #include "libc/nt/struct/overlapped.h" | ||||
| #include "libc/runtime/directmap.internal.h" | ||||
|  | @ -33,7 +34,6 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size, | |||
|                                                 int prot, int flags, | ||||
|                                                 int64_t handle, int64_t off) { | ||||
|   /* asan runtime depends on this function */ | ||||
|   bool32 rc; | ||||
|   uint32_t got; | ||||
|   size_t i, upsize; | ||||
|   struct DirectMap dm; | ||||
|  | @ -44,18 +44,12 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size, | |||
|      * combination of flags, that'll cause Windows to actually do this! | ||||
|      */ | ||||
|     upsize = ROUNDUP(size, FRAMESIZE); | ||||
|     dm.maphandle = CreateFileMappingNuma(-1, &kNtIsInheritable, | ||||
|                                          kNtPageExecuteReadwrite, upsize >> 32, | ||||
|                                          upsize, NULL, kNtNumaNoPreferredNode); | ||||
|     STRACE( | ||||
|         "CreateFileMappingNuma(-1, kNtPageExecuteReadwrite, %'zu/%'zu) -> %p", | ||||
|         upsize, size, dm.maphandle); | ||||
|     if (dm.maphandle) { | ||||
|       dm.addr = | ||||
|           MapViewOfFileExNuma(dm.maphandle, kNtFileMapWrite | kNtFileMapExecute, | ||||
|                               0, 0, upsize, addr, kNtNumaNoPreferredNode); | ||||
|       STRACE("MapViewOfFileExNuma(WX, %p) → addr:%p", addr, dm.addr); | ||||
|       if (dm.addr) { | ||||
|     if ((dm.maphandle = CreateFileMappingNuma( | ||||
|              -1, &kNtIsInheritable, kNtPageExecuteReadwrite, upsize >> 32, | ||||
|              upsize, NULL, kNtNumaNoPreferredNode))) { | ||||
|       if ((dm.addr = MapViewOfFileExNuma( | ||||
|                dm.maphandle, kNtFileMapWrite | kNtFileMapExecute, 0, 0, upsize, | ||||
|                addr, kNtNumaNoPreferredNode))) { | ||||
|         for (i = 0; i < size; i += got) { | ||||
|           got = 0; | ||||
|           op.Internal = 0; | ||||
|  | @ -69,37 +63,27 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size, | |||
|         if (i == size) { | ||||
|           return dm; | ||||
|         } | ||||
|         rc = UnmapViewOfFile(dm.addr); | ||||
|         STRACE("%s(addr:%p) → %hhhd% m", "UnmapViewOfFile", dm.maphandle, rc); | ||||
|         UnmapViewOfFile(dm.addr); | ||||
|       } | ||||
|       rc = CloseHandle(dm.maphandle); | ||||
|       STRACE("%s(%p) → %hhhd% m", "CloseHandle", dm.maphandle, rc); | ||||
|       CloseHandle(dm.maphandle); | ||||
|     } | ||||
|   } else { | ||||
|     dm.maphandle = CreateFileMappingNuma( | ||||
|     if ((dm.maphandle = CreateFileMappingNuma( | ||||
|              handle, &kNtIsInheritable, | ||||
|              (prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead, | ||||
|              handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL, | ||||
|         kNtNumaNoPreferredNode); | ||||
|     STRACE("CreateFileMappingNuma(fhand:%ld, prot:%s, size:%'zu) → %p", handle, | ||||
|            (prot & PROT_WRITE) ? "XRW" : "XR", handle != -1 ? 0 : size); | ||||
|     if (dm.maphandle) { | ||||
|       dm.addr = MapViewOfFileExNuma( | ||||
|              kNtNumaNoPreferredNode))) { | ||||
|       if ((dm.addr = MapViewOfFileExNuma( | ||||
|                dm.maphandle, | ||||
|                (prot & PROT_WRITE) ? kNtFileMapWrite | kNtFileMapExecute | ||||
|                                    : kNtFileMapRead | kNtFileMapExecute, | ||||
|           off >> 32, off, size, addr, kNtNumaNoPreferredNode); | ||||
|       STRACE("MapViewOfFileExNuma(prot:%s, off:%'ld, size:%'zu, addr:%p) → %p", | ||||
|              (prot & PROT_WRITE) ? "WX" : "RX", off, size, addr, dm.addr); | ||||
|       if (dm.addr) { | ||||
|                off >> 32, off, size, addr, kNtNumaNoPreferredNode))) { | ||||
|         return dm; | ||||
|       } else { | ||||
|         rc = CloseHandle(dm.maphandle); | ||||
|         STRACE("%s(%p) → %d% m", "CloseHandle", dm.maphandle, rc); | ||||
|       } | ||||
|       CloseHandle(dm.maphandle); | ||||
|     } | ||||
|   } | ||||
|   dm.maphandle = kNtInvalidHandleValue; | ||||
|   dm.addr = (void *)(intptr_t)__winerr(); | ||||
|   dm.addr = (void *)(intptr_t)-1; | ||||
|   return dm; | ||||
| } | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ | |||
| #include "libc/nt/struct/processinformation.h" | ||||
| #include "libc/nt/struct/startupinfo.h" | ||||
| #include "libc/nt/synchronization.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/o.h" | ||||
| 
 | ||||
|  | @ -54,5 +55,5 @@ textwindows int sys_execve_nt(const char *program, char *const argv[], | |||
|     GetExitCodeProcess(procinfo.hProcess, &dwExitCode); | ||||
|   } while (dwExitCode == kNtStillActive); | ||||
|   CloseHandle(procinfo.hProcess); | ||||
|   ExitProcess(dwExitCode); | ||||
|   _Exit(dwExitCode); | ||||
| } | ||||
|  |  | |||
|  | @ -16,7 +16,6 @@ | |||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #define ShouldUseMsabiAttribute() 1 | ||||
| #include "libc/bits/bits.h" | ||||
| #include "libc/calls/internal.h" | ||||
| #include "libc/calls/strace.internal.h" | ||||
|  | @ -52,7 +51,7 @@ noasan noubsan privileged int mprotect(void *addr, size_t len, int prot) { | |||
|       rc = -1; | ||||
|     } | ||||
|   } else { | ||||
|     if (__imp_VirtualProtect(addr, len, __prot2nt(prot, 0), &oldprot)) { | ||||
|     if (VirtualProtect(addr, len, __prot2nt(prot, 0), &oldprot)) { | ||||
|       rc = 0; | ||||
|     } else { | ||||
|       rc = __winerr(); | ||||
|  |  | |||
|  | @ -84,7 +84,7 @@ textwindows int ntspawn( | |||
|       (block = | ||||
|            MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0, | ||||
|                                blocksize, NULL, kNtNumaNoPreferredNode))) { | ||||
|     if (mkntcmdline(block->cmdline, prog, argv + 1) != -1 && | ||||
|     if (mkntcmdline(block->cmdline, prog, argv) != -1 && | ||||
|         mkntenvblock(block->envvars, envp, extravar) != -1) { | ||||
|       if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes, | ||||
|                         opt_lpThreadAttributes, bInheritHandles, | ||||
|  | @ -95,10 +95,11 @@ textwindows int ntspawn( | |||
|       } else { | ||||
|         __winerr(); | ||||
|       } | ||||
|       STRACE("CreateProcess(%#hs, %#hs) → %d% m", prog16, block->cmdline, rc); | ||||
|       STRACE("CreateProcess(%#hs, %!#hs) → %d% m", prog16, block->cmdline, rc); | ||||
|     } | ||||
|   } else { | ||||
|     __winerr(); | ||||
|     STRACE("ntspawn() alloc failed %m"); | ||||
|   } | ||||
|   if (block) UnmapViewOfFile(block); | ||||
|   if (handle) CloseHandle(handle); | ||||
|  |  | |||
|  | @ -18,10 +18,12 @@ | |||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/bits/pushpop.h" | ||||
| #include "libc/calls/internal.h" | ||||
| #include "libc/calls/strace.internal.h" | ||||
| #include "libc/calls/struct/siginfo.h" | ||||
| #include "libc/calls/typedef/sigaction_f.h" | ||||
| #include "libc/nt/enum/ctrlevent.h" | ||||
| #include "libc/nt/runtime.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/sysv/consts/sig.h" | ||||
| 
 | ||||
|  | @ -31,16 +33,20 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) { | |||
|   siginfo_t info; | ||||
|   switch (CtrlType) { | ||||
|     case kNtCtrlCEvent: | ||||
|       STRACE("kNtCtrlCEvent"); | ||||
|       sig = pushpop(SIGINT); | ||||
|       break; | ||||
|     case kNtCtrlBreakEvent: | ||||
|       STRACE("kNtCtrlBreakEvent"); | ||||
|       sig = pushpop(SIGQUIT); | ||||
|       break; | ||||
|     case kNtCtrlCloseEvent: | ||||
|       STRACE("kNtCtrlCloseEvent"); | ||||
|       sig = pushpop(SIGHUP); | ||||
|       break; | ||||
|     case kNtCtrlLogoffEvent:    // only received by services so hack hack hack
 | ||||
|     case kNtCtrlShutdownEvent:  // only received by services so hack hack hack
 | ||||
|       STRACE("kNtCtrlLogoffEvent"); | ||||
|       sig = pushpop(SIGALRM); | ||||
|       break; | ||||
|     default: | ||||
|  | @ -48,7 +54,7 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) { | |||
|   } | ||||
|   switch ((rva = __sighandrvas[sig])) { | ||||
|     case (uintptr_t)SIG_DFL: | ||||
|       ExitProcess(128 + sig); | ||||
|       _Exit(128 + sig); | ||||
|     case (uintptr_t)SIG_IGN: | ||||
|       return true; | ||||
|     default: | ||||
|  |  | |||
|  | @ -36,42 +36,82 @@ | |||
| #include "libc/sysv/consts/o.h" | ||||
| #include "libc/sysv/errfuns.h" | ||||
| 
 | ||||
| #define _O_APPEND     0x00000400 /* kNtFileAppendData */ | ||||
| #define _O_CREAT      0x00000040 /* kNtOpenAlways */ | ||||
| #define _O_EXCL       0x00000080 /* kNtCreateNew */ | ||||
| #define _O_TRUNC      0x00000200 /* kNtCreateAlways */ | ||||
| #define _O_DIRECTORY  0x00010000 /* kNtFileFlagBackupSemantics */ | ||||
| #define _O_TMPFILE    0x00410000 /* AttributeTemporary|FlagDeleteOnClose */ | ||||
| #define _O_DIRECT     0x00004000 /* kNtFileFlagNoBuffering */ | ||||
| #define _O_NDELAY     0x00000800 /* kNtFileFlagWriteThrough */ | ||||
| #define _O_RANDOM     0x80000000 /* kNtFileFlagRandomAccess */ | ||||
| #define _O_SEQUENTIAL 0x40000000 /* kNtFileFlagSequentialScan */ | ||||
| #define _O_COMPRESSED 0x20000000 /* kNtFileAttributeCompressed */ | ||||
| #define _O_INDEXED    0x10000000 /* !kNtFileAttributeNotContentIndexed */ | ||||
| #define _O_NONBLOCK   0x00000800 | ||||
| #define _O_CLOEXEC    0x00080000 | ||||
| 
 | ||||
| static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, | ||||
|                                             uint32_t flags, int32_t mode) { | ||||
|   uint32_t br; | ||||
|   int64_t handle; | ||||
|   char16_t path16[PATH_MAX]; | ||||
|   uint32_t perm, share, disp, attr; | ||||
|   if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; | ||||
|   if ((handle = CreateFile( | ||||
|            path16, flags & 0xf000000f, /* see consts.sh */ | ||||
|            (flags & O_EXCL) | ||||
|                ? kNtFileShareExclusive | ||||
|                : kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, | ||||
|            &kNtIsInheritable, | ||||
|            (flags & O_CREAT) && (flags & O_EXCL)    ? kNtCreateNew | ||||
|            : (flags & O_CREAT) && (flags & O_TRUNC) ? kNtCreateAlways | ||||
|            : (flags & O_CREAT)                      ? kNtOpenAlways | ||||
|            : (flags & O_TRUNC)                      ? kNtTruncateExisting | ||||
|                                                     : kNtOpenExisting, | ||||
|            /* TODO(jart): Should we just always set overlapped? */ | ||||
|            (/* note: content indexer demolishes unix-ey i/o performance */ | ||||
|             kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal | | ||||
|             (((flags & ((kNtFileFlagWriteThrough | kNtFileFlagOverlapped | | ||||
|                          kNtFileFlagNoBuffering | kNtFileFlagRandomAccess) >> | ||||
|                         8)) | ||||
|               << 8) | | ||||
|              (flags & (kNtFileFlagSequentialScan | kNtFileFlagDeleteOnClose | | ||||
|                        kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics | | ||||
|                        kNtFileAttributeTemporary)))), | ||||
| 
 | ||||
|   switch (flags & O_ACCMODE) { | ||||
|     case O_RDONLY: | ||||
|       perm = kNtFileGenericRead | kNtGenericExecute; | ||||
|       break; | ||||
|     case O_WRONLY: | ||||
|       perm = kNtFileGenericWrite | kNtGenericExecute; | ||||
|       break; | ||||
|     case O_RDWR: | ||||
|       perm = kNtFileGenericRead | kNtFileGenericWrite | kNtGenericExecute; | ||||
|       break; | ||||
|     default: | ||||
|       unreachable; | ||||
|   } | ||||
| 
 | ||||
|   if (flags & _O_EXCL) { | ||||
|     share = kNtFileShareExclusive; | ||||
|   } else { | ||||
|     share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete; | ||||
|   } | ||||
| 
 | ||||
|   if ((flags & _O_CREAT) && (flags & _O_EXCL)) { | ||||
|     disp = kNtCreateNew; | ||||
|   } else if ((flags & _O_CREAT) && (flags & _O_TRUNC)) { | ||||
|     disp = kNtCreateAlways; | ||||
|   } else if (flags & _O_CREAT) { | ||||
|     disp = kNtOpenAlways; | ||||
|   } else if (flags & _O_TRUNC) { | ||||
|     disp = kNtTruncateExisting; | ||||
|   } else { | ||||
|     disp = kNtOpenExisting; | ||||
|   } | ||||
| 
 | ||||
|   if ((flags & _O_TMPFILE) == _O_TMPFILE) { | ||||
|     attr = kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose; | ||||
|   } else { | ||||
|     attr = kNtFileAttributeNormal; | ||||
|     if (flags & _O_DIRECTORY) attr |= kNtFileFlagBackupSemantics; | ||||
|   } | ||||
|   flags |= kNtFileFlagOverlapped; | ||||
|   if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed; | ||||
|   if (flags & _O_COMPRESSED) attr |= kNtFileAttributeCompressed; | ||||
|   if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan; | ||||
|   if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess; | ||||
|   if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering; | ||||
|   if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough; | ||||
| 
 | ||||
|   if ((handle = CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr, | ||||
|                            0)) != -1) { | ||||
|   } else if (GetLastError() == kNtErrorFileExists && | ||||
|              ((flags & O_CREAT) && | ||||
|               (flags & O_TRUNC))) { /* TODO(jart): What was this? */ | ||||
|              ((flags & _O_CREAT) && | ||||
|               (flags & _O_TRUNC))) { /* TODO(jart): What was this? */ | ||||
|     handle = eisdir(); | ||||
|   } else { | ||||
|     handle = __winerr(); | ||||
|   } | ||||
|   STRACE("CreateFile() → %ld% m", handle); | ||||
|   return handle; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,8 +19,10 @@ | |||
| #include "libc/calls/calls.h" | ||||
| #include "libc/calls/getconsolectrlevent.h" | ||||
| #include "libc/calls/internal.h" | ||||
| #include "libc/calls/strace.internal.h" | ||||
| #include "libc/nt/console.h" | ||||
| #include "libc/nt/runtime.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/sysv/consts/sig.h" | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -32,6 +34,7 @@ | |||
|  */ | ||||
| int raise(int sig) { | ||||
|   int event; | ||||
|   STRACE("raise(%d)", sig); | ||||
|   if (sig == SIGTRAP) { | ||||
|     DebugBreak(); | ||||
|     return 0; | ||||
|  | @ -50,6 +53,6 @@ int raise(int sig) { | |||
|       return __winerr(); | ||||
|     } | ||||
|   } else { | ||||
|     ExitProcess(128 + sig); | ||||
|     _Exit(128 + sig); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -126,7 +126,6 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, | |||
|     } | ||||
|     CloseHandle(h); | ||||
|   } else { | ||||
|     STRACE("%s failed %m", "CreateFile(kNtFileFlagOpenReparsePoint)"); | ||||
|     rc = sys_readlinkat_nt_error(); | ||||
|   } | ||||
|   if (freeme && weaken(free)) { | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ | |||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/strace.internal.h" | ||||
| #include "libc/calls/struct/timespec.h" | ||||
| #include "libc/time/time.h" | ||||
| 
 | ||||
|  | @ -24,5 +25,8 @@ | |||
|  * @asyncsignalsafe | ||||
|  */ | ||||
| int sleep(uint32_t seconds) { | ||||
|   return nanosleep(&(struct timespec){seconds, 0}, NULL); | ||||
|   int rc; | ||||
|   rc = nanosleep(&(struct timespec){seconds, 0}, NULL); | ||||
|   STRACE("sleep(%u) → %d% m", seconds, rc); | ||||
|   return rc; | ||||
| } | ||||
|  |  | |||
|  | @ -1296,7 +1296,7 @@ void __asan_map_shadow(uintptr_t p, size_t n) { | |||
|     if (sm.addr == MAP_FAILED || | ||||
|         weaken(TrackMemoryInterval)( | ||||
|             m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE, | ||||
|             MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED) == -1) { | ||||
|             MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED, 0, size) == -1) { | ||||
|       kprintf("error: could not map asan shadow memory%n"); | ||||
|       __asan_die()(); | ||||
|       __asan_unreachable(); | ||||
|  |  | |||
							
								
								
									
										69
									
								
								libc/intrin/createfile.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								libc/intrin/createfile.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,69 @@ | |||
| /*-*- 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 2022 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/calls/strace.internal.h" | ||||
| #include "libc/intrin/describeflags.internal.h" | ||||
| #include "libc/nt/createfile.h" | ||||
| #include "libc/nt/enum/creationdisposition.h" | ||||
| #include "libc/nt/thunk/msabi.h" | ||||
| 
 | ||||
| extern typeof(CreateFile) *const __imp_CreateFileW __msabi; | ||||
| 
 | ||||
| static const char *DescribeDisposition(int x) { | ||||
|   switch (x) { | ||||
|     case kNtCreateNew: | ||||
|       return "kNtCreateNew"; | ||||
|     case kNtCreateAlways: | ||||
|       return "kNtCreateAlways"; | ||||
|     case kNtOpenExisting: | ||||
|       return "kNtOpenExisting"; | ||||
|     case kNtOpenAlways: | ||||
|       return "kNtOpenAlways"; | ||||
|     case kNtTruncateExisting: | ||||
|       return "kNtTruncateExisting"; | ||||
|     default: | ||||
|       return "wut"; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Opens file on the New Technology. | ||||
|  * | ||||
|  * @return handle, or -1 on failure | ||||
|  * @note this wrapper takes care of ABI, STRACE(), and __winerr() | ||||
|  * @see MapViewOfFileExNuma() | ||||
|  */ | ||||
| int64_t CreateFile(const char16_t *lpFileName, uint32_t dwDesiredAccess, | ||||
|                    uint32_t dwShareMode, | ||||
|                    struct NtSecurityAttributes *opt_lpSecurityAttributes, | ||||
|                    int dwCreationDisposition, uint32_t dwFlagsAndAttributes, | ||||
|                    int64_t opt_hTemplateFile) { | ||||
|   int64_t hHandle; | ||||
|   hHandle = __imp_CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, | ||||
|                               opt_lpSecurityAttributes, dwCreationDisposition, | ||||
|                               dwFlagsAndAttributes, opt_hTemplateFile); | ||||
|   if (hHandle == -1) __winerr(); | ||||
|   STRACE("CreateFile(%#hs, %s, %s, %p, %s, %s, %ld) → %ld% m", lpFileName, | ||||
|          DescribeNtFileAccessFlags(dwDesiredAccess), | ||||
|          DescribeNtFileShareFlags(dwShareMode), opt_lpSecurityAttributes, | ||||
|          DescribeDisposition(dwCreationDisposition), | ||||
|          DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), | ||||
|          opt_hTemplateFile, hHandle); | ||||
|   return hHandle; | ||||
| } | ||||
							
								
								
									
										51
									
								
								libc/intrin/createfilemappingnuma.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								libc/intrin/createfilemappingnuma.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | |||
| /*-*- 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 2022 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/calls/strace.internal.h" | ||||
| #include "libc/intrin/describeflags.internal.h" | ||||
| #include "libc/nt/memory.h" | ||||
| #include "libc/nt/struct/securityattributes.h" | ||||
| 
 | ||||
| extern typeof(CreateFileMappingNuma) *const | ||||
|     __imp_CreateFileMappingNumaW __msabi; | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates file mapping object on the New Technology. | ||||
|  * | ||||
|  * @param opt_hFile may be -1 for MAP_ANONYMOUS behavior | ||||
|  * @return handle, or 0 on failure | ||||
|  * @note this wrapper takes care of ABI, STRACE(), and __winerr() | ||||
|  * @see MapViewOfFileExNuma() | ||||
|  */ | ||||
| int64_t CreateFileMappingNuma( | ||||
|     int64_t opt_hFile, | ||||
|     const struct NtSecurityAttributes *opt_lpFileMappingAttributes, | ||||
|     uint32_t flProtect, uint32_t dwMaximumSizeHigh, uint32_t dwMaximumSizeLow, | ||||
|     const char16_t *opt_lpName, uint32_t nndDesiredNumaNode) { | ||||
|   int64_t hHandle; | ||||
|   hHandle = __imp_CreateFileMappingNumaW( | ||||
|       opt_hFile, opt_lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, | ||||
|       dwMaximumSizeLow, opt_lpName, nndDesiredNumaNode); | ||||
|   if (!hHandle) __winerr(); | ||||
|   STRACE("CreateFileMappingNuma(%ld, %s, max:%'zu, name:%#hs) → %ld% m", | ||||
|          opt_hFile, DescribeNtPageFlags(flProtect), | ||||
|          (uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName, | ||||
|          hHandle); | ||||
|   return hHandle; | ||||
| } | ||||
							
								
								
									
										59
									
								
								libc/intrin/describeflags.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								libc/intrin/describeflags.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| /*-*- 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 2022 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/intrin/describeflags.internal.h" | ||||
| #include "libc/intrin/kprintf.h" | ||||
| 
 | ||||
| const char *DescribeFlags(char *p, size_t n, struct DescribeFlags *d, size_t m, | ||||
|                           const char *prefix, unsigned x) { | ||||
|   bool t; | ||||
|   char b[21]; | ||||
|   size_t i, j, k; | ||||
|   for (t = i = j = 0; j < m; ++j) { | ||||
|     if ((x & d[j].flag) == d[j].flag) { | ||||
|       x &= ~d[j].flag; | ||||
|       if (t) { | ||||
|         if (i + 1 < n) p[i++] = '|'; | ||||
|       } else { | ||||
|         t = true; | ||||
|       } | ||||
|       for (k = 0; prefix && prefix[k]; ++k) { | ||||
|         if (i + 1 < n) p[i++] = prefix[k]; | ||||
|       } | ||||
|       for (k = 0; d[j].name[k]; ++k) { | ||||
|         if (i + 1 < n) p[i++] = d[j].name[k]; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   if (x || !t) { | ||||
|     if (t && i + 1 < n) p[i++] = '|'; | ||||
|     if (i + 1 < n) p[i++] = '0'; | ||||
|     if (x) { | ||||
|       if (i + 1 < n) p[i++] = 'x'; | ||||
|       k = 0; | ||||
|       do { | ||||
|         if (i + 1 < n) b[k++] = "0123456789abcdef"[x % 16]; | ||||
|       } while ((x /= 16)); | ||||
|       while (k--) { | ||||
|         if (i + 1 < n) p[i++] = b[k]; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   if (i < n) p[i] = 0; | ||||
|   return p; | ||||
| } | ||||
							
								
								
									
										21
									
								
								libc/intrin/describeflags.internal.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								libc/intrin/describeflags.internal.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| #ifndef COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_ | ||||
| #define COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_ | ||||
| #if !(__ASSEMBLER__ + __LINKER__ + 0) | ||||
| COSMOPOLITAN_C_START_ | ||||
| 
 | ||||
| struct thatispacked DescribeFlags { | ||||
|   unsigned flag; | ||||
|   const char *name; | ||||
| }; | ||||
| 
 | ||||
| const char *DescribeFlags(char *, size_t, struct DescribeFlags *, size_t, | ||||
|                           const char *, unsigned); | ||||
| const char *DescribeNtPageFlags(uint32_t); | ||||
| const char *DescribeNtFileMapFlags(uint32_t); | ||||
| const char *DescribeNtFileFlagsAndAttributes(uint32_t); | ||||
| const char *DescribeNtFileShareFlags(uint32_t); | ||||
| const char *DescribeNtFileAccessFlags(uint32_t); | ||||
| 
 | ||||
| COSMOPOLITAN_C_END_ | ||||
| #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||||
| #endif /* COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_ */ | ||||
							
								
								
									
										70
									
								
								libc/intrin/describentfileaccessflags.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								libc/intrin/describentfileaccessflags.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| /*-*- 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 2022 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/intrin/describeflags.internal.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/nt/enum/accessmask.h" | ||||
| #include "libc/nt/enum/filesharemode.h" | ||||
| 
 | ||||
| static const struct DescribeFlags kFileAccessflags[] = { | ||||
|     {kNtFileAllAccess, "FileAllAccess"},                    // order matters
 | ||||
|     {kNtFileGenericRead, "FileGenericRead"},                // order matters
 | ||||
|     {kNtFileGenericWrite, "FileGenericWrite"},              // order matters
 | ||||
|     {kNtFileGenericExecute, "FileGenericExecute"},          // order matters
 | ||||
|     {kNtGenericRead, "GenericRead"},                        //
 | ||||
|     {kNtGenericWrite, "GenericWrite"},                      //
 | ||||
|     {kNtGenericExecute, "GenericExecute"},                  //
 | ||||
|     {kNtGenericAll, "GenericAll"},                          //
 | ||||
|     {kNtDelete, "Delete"},                                  //
 | ||||
|     {kNtReadControl, "ReadControl"},                        //
 | ||||
|     {kNtWriteDac, "WriteDac"},                              //
 | ||||
|     {kNtWriteOwner, "WriteOwner"},                          //
 | ||||
|     {kNtSynchronize, "Synchronize"},                        //
 | ||||
|     {kNtStandardRightsRequired, "StandardRightsRequired"},  //
 | ||||
|     {kNtAccessSystemSecurity, "AccessSystemSecurity"},      //
 | ||||
|     {kNtMaximumAllowed, "MaximumAllowed"},                  //
 | ||||
|     {kNtFileReadData, "FileReadData"},                      //
 | ||||
|     {kNtFileListDirectory, "FileListDirectory"},            //
 | ||||
|     {kNtFileWriteData, "FileWriteData"},                    //
 | ||||
|     {kNtFileAddFile, "FileAddFile"},                        //
 | ||||
|     {kNtFileAppendData, "FileAppendData"},                  //
 | ||||
|     {kNtFileAddSubdirectory, "FileAddSubdirectory"},        //
 | ||||
|     {kNtFileCreatePipeInstance, "FileCreatePipeInstance"},  //
 | ||||
|     {kNtFileReadEa, "FileReadEa"},                          //
 | ||||
|     {kNtFileWriteEa, "FileWriteEa"},                        //
 | ||||
|     {kNtFileExecute, "FileExecute"},                        //
 | ||||
|     {kNtFileTraverse, "FileTraverse"},                      //
 | ||||
|     {kNtFileDeleteChild, "FileDeleteChild"},                //
 | ||||
|     {kNtFileReadAttributes, "FileReadAttributes"},          //
 | ||||
|     {kNtFileWriteAttributes, "FileWriteAttributes"},        //
 | ||||
|     {kNtTokenAssignPrimary, "TokenAssignPrimary"},          //
 | ||||
|     {kNtTokenDuplicate, "TokenDuplicate"},                  //
 | ||||
|     {kNtTokenImpersonate, "TokenImpersonate"},              //
 | ||||
|     {kNtTokenQuery, "TokenQuery"},                          //
 | ||||
|     {kNtTokenQuerySource, "TokenQuerySource"},              //
 | ||||
|     {kNtTokenAdjustPrivileges, "TokenAdjustPrivileges"},    //
 | ||||
|     {kNtTokenAdjustGroups, "TokenAdjustGroups"},            //
 | ||||
|     {kNtTokenAdjustDefault, "TokenAdjustDefault"},          //
 | ||||
|     {kNtTokenAdjustSessionid, "TokenAdjustSessionid"},      //
 | ||||
| }; | ||||
| 
 | ||||
| const char *DescribeNtFileAccessFlags(uint32_t x) { | ||||
|   static char ntfileaccessflags[256]; | ||||
|   return DescribeFlags(ntfileaccessflags, sizeof(ntfileaccessflags), | ||||
|                        kFileAccessflags, ARRAYLEN(kFileAccessflags), "kNt", x); | ||||
| } | ||||
							
								
								
									
										56
									
								
								libc/intrin/describentfileflagsandattributes.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								libc/intrin/describentfileflagsandattributes.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| /*-*- 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 2022 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/intrin/describeflags.internal.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/nt/enum/fileflagandattributes.h" | ||||
| 
 | ||||
| static const struct DescribeFlags kFileFlags[] = { | ||||
|     {kNtFileAttributeReadonly, "AttributeReadonly"},                    //
 | ||||
|     {kNtFileAttributeHidden, "AttributeHidden"},                        //
 | ||||
|     {kNtFileAttributeSystem, "AttributeSystem"},                        //
 | ||||
|     {kNtFileAttributeVolumelabel, "AttributeVolumelabel"},              //
 | ||||
|     {kNtFileAttributeDirectory, "AttributeDirectory"},                  //
 | ||||
|     {kNtFileAttributeArchive, "AttributeArchive"},                      //
 | ||||
|     {kNtFileAttributeDevice, "AttributeDevice"},                        //
 | ||||
|     {kNtFileAttributeNormal, "AttributeNormal"},                        //
 | ||||
|     {kNtFileAttributeTemporary, "AttributeTemporary"},                  //
 | ||||
|     {kNtFileAttributeSparseFile, "AttributeSparseFile"},                //
 | ||||
|     {kNtFileAttributeReparsePoint, "AttributeReparsePoint"},            //
 | ||||
|     {kNtFileAttributeCompressed, "AttributeCompressed"},                //
 | ||||
|     {kNtFileAttributeOffline, "AttributeOffline"},                      //
 | ||||
|     {kNtFileAttributeNotContentIndexed, "AttributeNotContentIndexed"},  //
 | ||||
|     {kNtFileAttributeEncrypted, "AttributeEncrypted"},                  //
 | ||||
|     {kNtFileFlagWriteThrough, "FlagWriteThrough"},                      //
 | ||||
|     {kNtFileFlagOverlapped, "FlagOverlapped"},                          //
 | ||||
|     {kNtFileFlagNoBuffering, "FlagNoBuffering"},                        //
 | ||||
|     {kNtFileFlagRandomAccess, "FlagRandomAccess"},                      //
 | ||||
|     {kNtFileFlagSequentialScan, "FlagSequentialScan"},                  //
 | ||||
|     {kNtFileFlagDeleteOnClose, "FlagDeleteOnClose"},                    //
 | ||||
|     {kNtFileFlagBackupSemantics, "FlagBackupSemantics"},                //
 | ||||
|     {kNtFileFlagPosixSemantics, "FlagPosixSemantics"},                  //
 | ||||
|     {kNtFileFlagOpenReparsePoint, "FlagOpenReparsePoint"},              //
 | ||||
|     {kNtFileFlagOpenNoRecall, "FlagOpenNoRecall"},                      //
 | ||||
|     {kNtFileFlagFirstPipeInstance, "FlagFirstPipeInstance"},            //
 | ||||
| }; | ||||
| 
 | ||||
| const char *DescribeNtFileFlagsAndAttributes(uint32_t x) { | ||||
|   static char ntfileflags[256]; | ||||
|   return DescribeFlags(ntfileflags, sizeof(ntfileflags), kFileFlags, | ||||
|                        ARRAYLEN(kFileFlags), "kNtFile", x); | ||||
| } | ||||
							
								
								
									
										37
									
								
								libc/intrin/describentfilemapflags.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								libc/intrin/describentfilemapflags.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| /*-*- 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 2022 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/intrin/describeflags.internal.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/nt/enum/filemapflags.h" | ||||
| 
 | ||||
| static const struct DescribeFlags kFileMapFlags[] = { | ||||
|     {kNtFileMapCopy, "Copy"},                      //
 | ||||
|     {kNtFileMapWrite, "Write"},                    //
 | ||||
|     {kNtFileMapRead, "Read"},                      //
 | ||||
|     {kNtFileMapExecute, "Execute"},                //
 | ||||
|     {kNtFileMapReserve, "Reserve"},                //
 | ||||
|     {kNtFileMapTargetsInvalid, "TargetsInvalid"},  //
 | ||||
|     {kNtFileMapLargePages, "LargePages"},          //
 | ||||
| }; | ||||
| 
 | ||||
| const char *DescribeNtFileMapFlags(uint32_t x) { | ||||
|   static char filemapflags[64]; | ||||
|   return DescribeFlags(filemapflags, sizeof(filemapflags), kFileMapFlags, | ||||
|                        ARRAYLEN(kFileMapFlags), "kNtFileMap", x); | ||||
| } | ||||
							
								
								
									
										34
									
								
								libc/intrin/describentfileshareflags.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								libc/intrin/describentfileshareflags.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| /*-*- 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 2022 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/intrin/describeflags.internal.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/nt/enum/filesharemode.h" | ||||
| 
 | ||||
| static const struct DescribeFlags kFileShareflags[] = { | ||||
|     {kNtFileShareRead, "Read"},      //
 | ||||
|     {kNtFileShareWrite, "Write"},    //
 | ||||
|     {kNtFileShareDelete, "Delete"},  //
 | ||||
| }; | ||||
| 
 | ||||
| const char *DescribeNtFileShareFlags(uint32_t x) { | ||||
|   static char ntfileshareflags[64]; | ||||
|   return DescribeFlags(ntfileshareflags, sizeof(ntfileshareflags), | ||||
|                        kFileShareflags, ARRAYLEN(kFileShareflags), | ||||
|                        "kNtFileShare", x); | ||||
| } | ||||
							
								
								
									
										48
									
								
								libc/intrin/describentpageflags.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								libc/intrin/describentpageflags.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| /*-*- 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 2022 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/intrin/describeflags.internal.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/nt/enum/pageflags.h" | ||||
| 
 | ||||
| static const struct DescribeFlags kPageFlags[] = { | ||||
|     {kNtPageNoaccess, "PageNoaccess"},                  //
 | ||||
|     {kNtPageReadonly, "PageReadonly"},                  //
 | ||||
|     {kNtPageReadwrite, "PageReadwrite"},                //
 | ||||
|     {kNtPageWritecopy, "PageWritecopy"},                //
 | ||||
|     {kNtPageExecute, "PageExecute"},                    //
 | ||||
|     {kNtPageExecuteRead, "PageExecuteRead"},            //
 | ||||
|     {kNtPageExecuteReadwrite, "PageExecuteReadwrite"},  //
 | ||||
|     {kNtPageExecuteWritecopy, "PageExecuteWritecopy"},  //
 | ||||
|     {kNtPageGuard, "PageGuard"},                        //
 | ||||
|     {kNtPageNocache, "PageNocache"},                    //
 | ||||
|     {kNtPageWritecombine, "PageWritecombine"},          //
 | ||||
|     {kNtSecReserve, "SecReserve"},                      //
 | ||||
|     {kNtSecCommit, "SecCommit"},                        //
 | ||||
|     {kNtSecImageNoExecute, "SecImageNoExecute"},        // order matters
 | ||||
|     {kNtSecImage, "SecImage"},                          //
 | ||||
|     {kNtSecLargePages, "SecLargePages"},                //
 | ||||
|     {kNtSecNocache, "SecNocache"},                      //
 | ||||
|     {kNtSecWritecombine, "SecWritecombine"},            //
 | ||||
| }; | ||||
| 
 | ||||
| const char *DescribeNtPageFlags(uint32_t x) { | ||||
|   static char pageflags[64]; | ||||
|   return DescribeFlags(pageflags, sizeof(pageflags), kPageFlags, | ||||
|                        ARRAYLEN(kPageFlags), "kNt", x); | ||||
| } | ||||
|  | @ -20,12 +20,17 @@ | |||
| #include "libc/calls/internal.h" | ||||
| #include "libc/calls/strace.internal.h" | ||||
| #include "libc/dce.h" | ||||
| #include "libc/intrin/kprintf.h" | ||||
| #include "libc/nexgen32e/vendor.internal.h" | ||||
| #include "libc/nt/console.h" | ||||
| #include "libc/nt/process.h" | ||||
| #include "libc/nt/runtime.h" | ||||
| #include "libc/nt/thunk/msabi.h" | ||||
| #include "libc/runtime/internal.h" | ||||
| #include "libc/sysv/consts/nr.h" | ||||
| 
 | ||||
| uint32_t __winmainpid; | ||||
| const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle}; | ||||
| 
 | ||||
| /**
 | ||||
|  * Terminates process, ignoring destructors and atexit() handlers. | ||||
|  * | ||||
|  | @ -38,7 +43,13 @@ | |||
|  * @noreturn | ||||
|  */ | ||||
| privileged noinstrument noasan noubsan wontreturn void _Exit(int exitcode) { | ||||
|   int i; | ||||
|   STRACE("_Exit(%d)", exitcode); | ||||
|   if (SupportsWindows() && GetCurrentProcessId() == __winmainpid) { | ||||
|     for (i = 0; i < 2; ++i) { | ||||
|       SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]); | ||||
|     } | ||||
|   } | ||||
|   if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) { | ||||
|     asm volatile("syscall" | ||||
|                  : /* no outputs */ | ||||
|  |  | |||
|  | @ -57,11 +57,23 @@ o/$(MODE)/libc/intrin/asan.o:				\ | |||
| 			-finline			\
 | ||||
| 			-finline-functions | ||||
| 
 | ||||
| o/$(MODE)/libc/intrin/kprintf.greg.o:			\ | ||||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			-fpie				\
 | ||||
| 			-ffreestanding			\
 | ||||
| 			$(NO_MAGIC) | ||||
| 
 | ||||
| o/$(MODE)/libc/intrin/createfile.greg.o			\ | ||||
| o/$(MODE)/libc/intrin/describeflags.greg.o		\ | ||||
| o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o	\ | ||||
| o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o	\ | ||||
| o/$(MODE)/libc/intrin/kstarttsc.o			\ | ||||
| o/$(MODE)/libc/intrin/nomultics.o			\ | ||||
| o/$(MODE)/libc/intrin/ntconsolemode.o:			\ | ||||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			-fno-sanitize=all | ||||
| 			-Os				\
 | ||||
| 			-ffreestanding			\
 | ||||
| 			$(NO_MAGIC) | ||||
| 
 | ||||
| o/$(MODE)/libc/intrin/asan.o				\ | ||||
| o/$(MODE)/libc/intrin/ubsan.o:				\ | ||||
|  | @ -86,13 +98,6 @@ o/$(MODE)/libc/intrin/memmove.o:			\ | |||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			-fpie | ||||
| 
 | ||||
| o/$(MODE)/libc/intrin/kprintf.greg.o:			\ | ||||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			-fpie				\
 | ||||
| 			-fwrapv				\
 | ||||
| 			-fno-sanitize=all		\
 | ||||
| 			-fschedule-insns2 | ||||
| 
 | ||||
| LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x))) | ||||
| LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS)) | ||||
| LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS)) | ||||
|  |  | |||
|  | @ -54,16 +54,16 @@ struct Timestamps { | |||
| extern int __pid; | ||||
| extern bool __replmode; | ||||
| extern bool __nomultics; | ||||
| static volatile unsigned long long kbirth; | ||||
| volatile unsigned long long __kbirth; | ||||
| 
 | ||||
| privileged static struct Timestamps kenter(void) { | ||||
|   struct Timestamps ts; | ||||
|   ts.start = rdtsc(); | ||||
|   ts.birth = kbirth; | ||||
|   ts.birth = __kbirth; | ||||
|   if (!ts.birth) { | ||||
|     ts.birth = kStartTsc; | ||||
|     if (!ts.birth) ts.birth = 1; | ||||
|     cmpxchg(&kbirth, 0, ts.birth); | ||||
|     cmpxchg(&__kbirth, 0, ts.birth); | ||||
|   } | ||||
|   return ts; | ||||
| } | ||||
|  | @ -74,7 +74,7 @@ privileged static void kleave(struct Timestamps ts) { | |||
|   elapse = unsignedsubtract(finish, ts.start); | ||||
|   adjust = ts.birth + elapse; | ||||
|   if (!adjust) adjust = 1; | ||||
|   cmpxchg(&kbirth, ts.birth, adjust); /* ignore overlapping time intervals */ | ||||
|   cmpxchg(&__kbirth, ts.birth, adjust); /* ignore overlapping time intervals */ | ||||
| } | ||||
| 
 | ||||
| privileged static inline char *kadvance(char *p, char *e, long n) { | ||||
|  | @ -465,7 +465,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, | |||
|           } | ||||
|           goto EmitChar; | ||||
|         case 'm': | ||||
|           if (!(x = errno) && sign == ' ') { | ||||
|           if (!(x = errno) && sign == ' ' && | ||||
|               (!IsWindows() || !__imp_GetLastError())) { | ||||
|             break; | ||||
|           } else if (weaken(strerror_r) && | ||||
|                      !weaken(strerror_r)(x, z, sizeof(z))) { | ||||
|  | @ -572,7 +573,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, | |||
|                 goto EmitChar; | ||||
|               } | ||||
|             } else if (type < -1) { | ||||
|               if ((t = *s++ & 255)) { | ||||
|               if ((t = *s++ & 255) || prec) { | ||||
|                 t = kCp437[t]; | ||||
|               } | ||||
|             } else if (type < 0) { | ||||
|  |  | |||
							
								
								
									
										52
									
								
								libc/intrin/mapviewoffileexnuma.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								libc/intrin/mapviewoffileexnuma.greg.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | |||
| /*-*- 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 2022 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/calls/internal.h" | ||||
| #include "libc/calls/strace.internal.h" | ||||
| #include "libc/intrin/describeflags.internal.h" | ||||
| #include "libc/nt/enum/filemapflags.h" | ||||
| #include "libc/nt/memory.h" | ||||
| 
 | ||||
| extern typeof(MapViewOfFileExNuma) *const __imp_MapViewOfFileExNuma __msabi; | ||||
| 
 | ||||
| /**
 | ||||
|  * Maps view of file mapping into memory on the New Technology. | ||||
|  * | ||||
|  * @param hFileMappingObject was returned by CreateFileMapping() | ||||
|  * @param dwDesiredAccess has kNtFileMap... flags | ||||
|  * @param opt_lpDesiredBaseAddress may be NULL to let o/s choose | ||||
|  * @return base address, or NULL on failure | ||||
|  * @note this wrapper takes care of ABI, STRACE(), and __winerr() | ||||
|  */ | ||||
| void *MapViewOfFileExNuma(int64_t hFileMappingObject, uint32_t dwDesiredAccess, | ||||
|                           uint32_t dwFileOffsetHigh, uint32_t dwFileOffsetLow, | ||||
|                           size_t dwNumberOfBytesToMap, | ||||
|                           void *opt_lpDesiredBaseAddress, | ||||
|                           uint32_t nndDesiredNumaNode) { | ||||
|   void *pStartingAddress; | ||||
|   pStartingAddress = __imp_MapViewOfFileExNuma( | ||||
|       hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, | ||||
|       dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, nndDesiredNumaNode); | ||||
|   if (!pStartingAddress) __winerr(); | ||||
|   STRACE("MapViewOfFileExNuma(%ld, %s, off:%'ld, size:%'zu, %p) → %p% m", | ||||
|          hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess), | ||||
|          (uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow, | ||||
|          dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress); | ||||
|   return pStartingAddress; | ||||
| } | ||||
|  | @ -18,32 +18,21 @@ | |||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/calls/internal.h" | ||||
| #include "libc/nt/enum/pageflags.h" | ||||
| #include "libc/nt/memory.h" | ||||
| #include "libc/sysv/consts/map.h" | ||||
| #include "libc/sysv/consts/prot.h" | ||||
| 
 | ||||
| #define HAS(X, BITS) (((X) & (BITS)) == (BITS)) | ||||
| 
 | ||||
| /**
 | ||||
|  * Converts System Five memory protection flags to Windows NT, Part 1. | ||||
|  * @see libc/sysv/consts.sh | ||||
|  */ | ||||
| privileged uint32_t __prot2nt(int prot, int flags) { | ||||
|   return (HAS(prot, PROT_READ | PROT_WRITE | PROT_EXEC) | ||||
|               ? (HAS(flags, MAP_SHARED) || HAS(flags, MAP_ANONYMOUS)) | ||||
|                     ? kNtPageExecuteReadwrite | ||||
|                     : kNtPageExecuteWritecopy | ||||
|               : HAS(prot, PROT_READ | PROT_WRITE) | ||||
|                     ? (HAS(flags, MAP_SHARED) || HAS(flags, MAP_ANONYMOUS)) | ||||
|                           ? kNtPageReadwrite | ||||
|                           : kNtPageReadwrite /* kNtPageWritecopy */ | ||||
|                     : HAS(prot, PROT_READ | PROT_EXEC) | ||||
|                           ? kNtPageExecuteRead | ||||
|                           : HAS(prot, PROT_EXEC) | ||||
|                                 ? kNtPageExecute | ||||
|                                 : HAS(prot, PROT_READ) ? kNtPageReadonly | ||||
|                                                        : kNtPageNoaccess) | | ||||
|          ((prot | flags) & | ||||
|           (kNtSecReserve | kNtSecCommit | kNtSecImage | kNtSecImageNoExecute | | ||||
|            kNtSecLargePages | kNtSecNocache | kNtSecWritecombine)); | ||||
|   switch (prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) { | ||||
|     case PROT_READ: | ||||
|       return kNtPageReadonly; | ||||
|     case PROT_WRITE: | ||||
|     case PROT_READ | PROT_WRITE: | ||||
|       return kNtPageReadwrite; | ||||
|     case PROT_READ | PROT_EXEC: | ||||
|       return kNtPageExecuteRead; | ||||
|     case PROT_WRITE | PROT_EXEC: | ||||
|     case PROT_READ | PROT_WRITE | PROT_EXEC: | ||||
|       return kNtPageExecuteReadwrite; | ||||
|     default: | ||||
|       return kNtPageNoaccess; | ||||
|   } | ||||
| } | ||||
|  | @ -25,8 +25,6 @@ | |||
| #include "libc/runtime/runtime.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| 
 | ||||
| const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle}; | ||||
| 
 | ||||
| /**
 | ||||
|  * Exits process faster. | ||||
|  * | ||||
|  | @ -40,11 +38,6 @@ wontreturn void quick_exit(int exitcode) { | |||
|   if (weaken(fflush)) { | ||||
|     weaken(fflush)(0); | ||||
|   } | ||||
|   if (SupportsWindows() && __ntconsolemode[0]) { | ||||
|     for (i = 0; i < 2; ++i) { | ||||
|       SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]); | ||||
|     } | ||||
|   } | ||||
|   for (p = __fini_array_end; p > __fini_array_start;) { | ||||
|     ((void (*)(void))(*--p))(); | ||||
|   } | ||||
|  |  | |||
							
								
								
									
										39
									
								
								libc/intrin/virtualprotect.greg.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								libc/intrin/virtualprotect.greg.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 2022 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/calls/strace.internal.h" | ||||
| #include "libc/intrin/describeflags.internal.h" | ||||
| #include "libc/nt/memory.h" | ||||
| 
 | ||||
| extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi; | ||||
| 
 | ||||
| /**
 | ||||
|  * Protects memory on the New Technology. | ||||
|  * @note this wrapper takes care of ABI, STRACE(), and __winerr() | ||||
|  */ | ||||
| bool32 VirtualProtect(void *lpAddress, uint64_t dwSize, uint32_t flNewProtect, | ||||
|                       uint32_t *lpflOldProtect) { | ||||
|   bool32 bOk; | ||||
|   bOk = __imp_VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); | ||||
|   if (!bOk) __winerr(); | ||||
|   STRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize, | ||||
|          DescribeNtPageFlags(flNewProtect), | ||||
|          DescribeNtPageFlags(*lpflOldProtect), bOk); | ||||
|   return bOk; | ||||
| } | ||||
|  | @ -38,7 +38,7 @@ relegated wontreturn void __die(void) { | |||
|       DebugBreak(); | ||||
|     } | ||||
|     ShowBacktrace(2, NULL); | ||||
|     quick_exit(77); | ||||
|     _Exit(77); | ||||
|   } | ||||
|   __write_str("PANIC: __DIE() DIED\r\n"); | ||||
|   _Exit(78); | ||||
|  |  | |||
|  | @ -316,7 +316,7 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si, | |||
|       if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) { | ||||
|         __restore_tty(1); | ||||
|         ShowCrashReport(err, sig, si, ctx); | ||||
|         quick_exit(128 + sig); | ||||
|         _Exit(128 + sig); | ||||
|       } | ||||
|     } else { | ||||
|       __minicrash(sig, si, ctx, "WHILE VFORKED"); | ||||
|  |  | |||
							
								
								
									
										9
									
								
								libc/nt/enum/heap.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								libc/nt/enum/heap.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| #ifndef COSMOPOLITAN_LIBC_NT_ENUM_HEAP_H_ | ||||
| #define COSMOPOLITAN_LIBC_NT_ENUM_HEAP_H_ | ||||
| 
 | ||||
| #define kNtHeapNoSerialize        1 | ||||
| #define kNtHeapGenerateExceptions 4 | ||||
| #define kNtHeapZeroMemory         8 | ||||
| #define kNtHeapReallocInPlaceOnly 16 | ||||
| 
 | ||||
| #endif /* COSMOPOLITAN_LIBC_NT_ENUM_HEAP_H_ */ | ||||
|  | @ -2,25 +2,25 @@ | |||
| #define COSMOPOLITAN_LIBC_NT_ENUM_PAGEFLAGS_H_ | ||||
| 
 | ||||
| /* Pick One */ | ||||
| #define kNtPageNoaccess 0x01 | ||||
| #define kNtPageReadonly 0x02 | ||||
| #define kNtPageReadwrite 0x04 | ||||
| #define kNtPageWritecopy 0x08 | ||||
| #define kNtPageExecute 0x10 | ||||
| #define kNtPageExecuteRead 0x20 | ||||
| #define kNtPageExecuteReadwrite 0x40 | ||||
| #define kNtPageExecuteWritecopy 0x80 | ||||
| #define kNtPageNoaccess         0x001 | ||||
| #define kNtPageReadonly         0x002 | ||||
| #define kNtPageReadwrite        0x004 | ||||
| #define kNtPageWritecopy        0x008 | ||||
| #define kNtPageExecute          0x010 | ||||
| #define kNtPageExecuteRead      0x020 | ||||
| #define kNtPageExecuteReadwrite 0x040 | ||||
| #define kNtPageExecuteWritecopy 0x080 | ||||
| #define kNtPageGuard            0x100 | ||||
| #define kNtPageNocache          0x200 | ||||
| #define kNtPageWritecombine     0x400 | ||||
| 
 | ||||
| /* These may be OR'd */ | ||||
| #define kNtSecReserve 0x4000000 | ||||
| #define kNtSecCommit 0x8000000 /* ←default */ | ||||
| #define kNtSecImage 0x1000000 | ||||
| #define kNtSecReserve        0x04000000 | ||||
| #define kNtSecCommit         0x08000000 /* default */ | ||||
| #define kNtSecImageNoExecute 0x11000000 | ||||
| #define kNtSecLargePages 0x80000000 | ||||
| #define kNtSecImage          0x01000000 | ||||
| #define kNtSecNocache        0x10000000 | ||||
| #define kNtSecLargePages     0x80000000 | ||||
| #define kNtSecWritecombine   0x40000000 | ||||
| 
 | ||||
| #endif /* COSMOPOLITAN_LIBC_NT_ENUM_PAGEFLAGS_H_ */ | ||||
|  |  | |||
|  | @ -2,11 +2,11 @@ | |||
| .imp	kernel32,__imp_CreateFileMappingNumaW,CreateFileMappingNumaW,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| CreateFileMappingNuma: | ||||
| __CreateFileMappingNuma: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_CreateFileMappingNumaW(%rip),%rax | ||||
| 	jmp	__sysv2nt8 | ||||
| 	.endfn	CreateFileMappingNuma,globl | ||||
| 	.endfn	__CreateFileMappingNuma,globl | ||||
| 	.previous | ||||
|  |  | |||
|  | @ -2,11 +2,11 @@ | |||
| .imp	kernel32,__imp_CreateFileW,CreateFileW,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| CreateFile: | ||||
| __CreateFile: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_CreateFileW(%rip),%rax | ||||
| 	jmp	__sysv2nt8 | ||||
| 	.endfn	CreateFile,globl | ||||
| 	.endfn	__CreateFile,globl | ||||
| 	.previous | ||||
|  |  | |||
|  | @ -1,2 +1,14 @@ | |||
| .include "o/libc/nt/codegen.inc" | ||||
| .imp	kernel32,__imp_GetProcessHeap,GetProcessHeap,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| GetProcessHeap: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	sub	$32,%rsp | ||||
| 	call	*__imp_GetProcessHeap(%rip) | ||||
| 	leave | ||||
| 	ret | ||||
| 	.endfn	GetProcessHeap,globl | ||||
| 	.previous | ||||
|  |  | |||
|  | @ -1,2 +1,12 @@ | |||
| .include "o/libc/nt/codegen.inc" | ||||
| .imp	kernel32,__imp_GetProcessHeaps,GetProcessHeaps,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| GetProcessHeaps: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_GetProcessHeaps(%rip),%rax | ||||
| 	jmp	__sysv2nt | ||||
| 	.endfn	GetProcessHeaps,globl | ||||
| 	.previous | ||||
|  |  | |||
							
								
								
									
										12
									
								
								libc/nt/kernel32/HeapAlloc.s
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libc/nt/kernel32/HeapAlloc.s
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| .include "o/libc/nt/codegen.inc" | ||||
| .imp	kernel32,__imp_HeapAlloc,HeapAlloc,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| HeapAlloc: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_HeapAlloc(%rip),%rax | ||||
| 	jmp	__sysv2nt | ||||
| 	.endfn	HeapAlloc,globl | ||||
| 	.previous | ||||
|  | @ -1,2 +1,12 @@ | |||
| .include "o/libc/nt/codegen.inc" | ||||
| .imp	kernel32,__imp_HeapCompact,HeapCompact,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| HeapCompact: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_HeapCompact(%rip),%rax | ||||
| 	jmp	__sysv2nt | ||||
| 	.endfn	HeapCompact,globl | ||||
| 	.previous | ||||
|  |  | |||
|  | @ -1,2 +1,12 @@ | |||
| .include "o/libc/nt/codegen.inc" | ||||
| .imp	kernel32,__imp_HeapCreate,HeapCreate,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| HeapCreate: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_HeapCreate(%rip),%rax | ||||
| 	jmp	__sysv2nt | ||||
| 	.endfn	HeapCreate,globl | ||||
| 	.previous | ||||
|  |  | |||
|  | @ -1,2 +1,15 @@ | |||
| .include "o/libc/nt/codegen.inc" | ||||
| .imp	kernel32,__imp_HeapDestroy,HeapDestroy,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| HeapDestroy: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	%rdi,%rcx | ||||
| 	sub	$32,%rsp | ||||
| 	call	*__imp_HeapDestroy(%rip) | ||||
| 	leave | ||||
| 	ret | ||||
| 	.endfn	HeapDestroy,globl | ||||
| 	.previous | ||||
|  |  | |||
|  | @ -1,2 +1,12 @@ | |||
| .include "o/libc/nt/codegen.inc" | ||||
| .imp	kernel32,__imp_HeapFree,HeapFree,847 | ||||
| 
 | ||||
| 	.text.windows | ||||
| HeapFree: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_HeapFree(%rip),%rax | ||||
| 	jmp	__sysv2nt | ||||
| 	.endfn	HeapFree,globl | ||||
| 	.previous | ||||
|  |  | |||
							
								
								
									
										12
									
								
								libc/nt/kernel32/HeapReAlloc.s
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libc/nt/kernel32/HeapReAlloc.s
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| .include "o/libc/nt/codegen.inc" | ||||
| .imp	kernel32,__imp_HeapReAlloc,HeapReAlloc,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| HeapReAlloc: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_HeapReAlloc(%rip),%rax | ||||
| 	jmp	__sysv2nt | ||||
| 	.endfn	HeapReAlloc,globl | ||||
| 	.previous | ||||
|  | @ -2,11 +2,11 @@ | |||
| .imp	kernel32,__imp_MapViewOfFileExNuma,MapViewOfFileExNuma,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| MapViewOfFileExNuma: | ||||
| __MapViewOfFileExNuma: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_MapViewOfFileExNuma(%rip),%rax | ||||
| 	jmp	__sysv2nt8 | ||||
| 	.endfn	MapViewOfFileExNuma,globl | ||||
| 	.endfn	__MapViewOfFileExNuma,globl | ||||
| 	.previous | ||||
|  |  | |||
|  | @ -2,11 +2,11 @@ | |||
| .imp	kernel32,__imp_VirtualProtect,VirtualProtect,0 | ||||
| 
 | ||||
| 	.text.windows | ||||
| VirtualProtect: | ||||
| __VirtualProtect: | ||||
| 	push	%rbp | ||||
| 	mov	%rsp,%rbp | ||||
| 	.profilable | ||||
| 	mov	__imp_VirtualProtect(%rip),%rax | ||||
| 	jmp	__sysv2nt | ||||
| 	.endfn	VirtualProtect,globl | ||||
| 	.endfn	__VirtualProtect,globl | ||||
| 	.previous | ||||
|  |  | |||
|  | @ -593,9 +593,10 @@ imp	'CreateEventEx'						CreateEventExW						kernel32	0	4	# KernelBase | |||
| imp	'CreateEvent'						CreateEventW						kernel32	0	4	# KernelBase | ||||
| imp	'CreateFiber'						CreateFiber						kernel32	0		# KernelBase | ||||
| imp	'CreateFiberEx'						CreateFiberEx						kernel32	0		# KernelBase | ||||
| imp	'CreateFile'						CreateFileW						kernel32	0	7	# KernelBase | ||||
| imp	'CreateFileA'						CreateFileA						kernel32	0	7	# KernelBase | ||||
| imp	'CreateFileMappingNuma'					CreateFileMappingNumaW					kernel32	0	7	# Kernelbase | ||||
| imp	'__CreateFile'						CreateFileW						kernel32	0	7	# KernelBase | ||||
| imp	'__CreateFileMappingNuma'				CreateFileMappingNumaW					kernel32	0	7	# Kernelbase | ||||
| imp	'__MapViewOfFileExNuma'					MapViewOfFileExNuma					kernel32	0	7	# KernelBase | ||||
| imp	'CreateFileMappingNumaA'				CreateFileMappingNumaA					kernel32	198	7 | ||||
| imp	'CreateFileMapping'					CreateFileMappingW					kernel32	0	7	# KernelBase | ||||
| imp	'CreateFileMappingA'					CreateFileMappingA					kernel32	196	7 | ||||
|  | @ -2474,8 +2475,8 @@ imp	'GetProcessDefaultLayout'				GetProcessDefaultLayout					user32		1930 | |||
| imp	'GetProcessDpiAwarenessInternal'			GetProcessDpiAwarenessInternal				user32		1931 | ||||
| imp	'GetProcessGroupAffinity'				GetProcessGroupAffinity					kernel32	0		# KernelBase | ||||
| imp	'GetProcessHandleCount'					GetProcessHandleCount					kernel32	0	2	# KernelBase | ||||
| imp	'GetProcessHeap'					GetProcessHeap						kernel32	0		# KernelBase | ||||
| imp	'GetProcessHeaps'					GetProcessHeaps						kernel32	0		# KernelBase | ||||
| imp	'GetProcessHeap'					GetProcessHeap						kernel32	0	0	# KernelBase | ||||
| imp	'GetProcessHeaps'					GetProcessHeaps						kernel32	0	2	# KernelBase | ||||
| imp	'GetProcessId'						GetProcessId						kernel32	0	1	# KernelBase | ||||
| imp	'GetProcessIdOfThread'					GetProcessIdOfThread					kernel32	0	1	# KernelBase | ||||
| imp	'GetProcessImageFileNameA'				GetProcessImageFileNameA				kernel32	676	3 | ||||
|  | @ -2817,10 +2818,12 @@ imp	'Heap32First'						Heap32First						kernel32	839 | |||
| imp	'Heap32ListFirst'					Heap32ListFirst						kernel32	840 | ||||
| imp	'Heap32ListNext'					Heap32ListNext						kernel32	841 | ||||
| imp	'Heap32Next'						Heap32Next						kernel32	842 | ||||
| imp	'HeapCompact'						HeapCompact						kernel32	0		# KernelBase | ||||
| imp	'HeapCreate'						HeapCreate						kernel32	0		# KernelBase | ||||
| imp	'HeapDestroy'						HeapDestroy						kernel32	0		# KernelBase | ||||
| imp	'HeapFree'						HeapFree						kernel32	847 | ||||
| imp	'HeapCompact'						HeapCompact						kernel32	0	2	# KernelBase | ||||
| imp	'HeapAlloc'						HeapAlloc						kernel32	0	3 | ||||
| imp	'HeapReAlloc'						HeapReAlloc						kernel32	0	4 | ||||
| imp	'HeapCreate'						HeapCreate						kernel32	0	3	# KernelBase | ||||
| imp	'HeapDestroy'						HeapDestroy						kernel32	0	1	# KernelBase | ||||
| imp	'HeapFree'						HeapFree						kernel32	847	3 | ||||
| imp	'HeapLock'						HeapLock						kernel32	0		# KernelBase | ||||
| imp	'HeapQueryInformation'					HeapQueryInformation					kernel32	0		# KernelBase | ||||
| imp	'HeapSetInformation'					HeapSetInformation					kernel32	0		# KernelBase | ||||
|  | @ -3380,7 +3383,6 @@ imp	'MapViewOfFile'						MapViewOfFile						kernel32	0		# KernelBase | |||
| imp	'MapViewOfFile3'					MapViewOfFile3						KernelBase	1003 | ||||
| imp	'MapViewOfFile3FromApp'					MapViewOfFile3FromApp					KernelBase	1004 | ||||
| imp	'MapViewOfFileEx'					MapViewOfFileEx						kernel32	0		# KernelBase | ||||
| imp	'MapViewOfFileExNuma'					MapViewOfFileExNuma					kernel32	0	7	# KernelBase | ||||
| imp	'MapViewOfFileFromApp'					MapViewOfFileFromApp					kernel32	0		# KernelBase | ||||
| imp	'MapViewOfFileNuma2'					MapViewOfFileNuma2					KernelBase	1008 | ||||
| imp	'MapVirtualKeyA'					MapVirtualKeyA						user32		2153 | ||||
|  | @ -6879,7 +6881,7 @@ imp	'VirtualAllocFromApp'					VirtualAllocFromApp					KernelBase	1760 | |||
| imp	'VirtualFree'						VirtualFree						kernel32	0	3	# KernelBase | ||||
| imp	'VirtualFreeEx'						VirtualFreeEx						kernel32	0		# KernelBase | ||||
| imp	'VirtualLock'						VirtualLock						kernel32	0		# KernelBase | ||||
| imp	'VirtualProtect'					VirtualProtect						kernel32	0	4	# KernelBase | ||||
| imp	'__VirtualProtect'					VirtualProtect						kernel32	0	4	# KernelBase | ||||
| imp	'VirtualProtectEx'					VirtualProtectEx					kernel32	0		# KernelBase | ||||
| imp	'VirtualProtectFromApp'					VirtualProtectFromApp					KernelBase	1766 | ||||
| imp	'VirtualQuery'						VirtualQuery						kernel32	0	3	# KernelBase | ||||
|  |  | |||
|  | @ -70,6 +70,12 @@ bool32 PrefetchVirtualMemory(int64_t hProcess, const uint32_t *NumberOfEntries, | |||
| bool32 OfferVirtualMemory(void *inout_VirtualAddress, size_t Size, | ||||
|                           int Priority); | ||||
| 
 | ||||
| int64_t GetProcessHeap(void); | ||||
| void *HeapAlloc(int64_t hHeap, uint32_t dwFlags, size_t dwBytes) nodiscard; | ||||
| bool32 HeapFree(int64_t hHeap, uint32_t dwFlags, void *opt_lpMem); | ||||
| void *HeapReAlloc(int64_t hHeap, uint32_t dwFlags, void *lpMem, | ||||
|                   size_t dwBytes) nodiscard; | ||||
| 
 | ||||
| void *GlobalAlloc(uint32_t uFlags, uint64_t dwBytes) nodiscard; | ||||
| void *GlobalFree(void *hMem); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,12 +1,6 @@ | |||
| #define CreateFileMappingNuma(...) __imp_CreateFileMappingNumaW(__VA_ARGS__)
 | ||||
| #define MapViewOfFileExNuma(...)   __imp_MapViewOfFileExNuma(__VA_ARGS__)
 | ||||
| #define FlushViewOfFile(...) __imp_FlushViewOfFile(__VA_ARGS__)
 | ||||
| #define UnmapViewOfFile(...) __imp_UnmapViewOfFile(__VA_ARGS__)
 | ||||
| 
 | ||||
| extern typeof(LocalFree) *const __imp_LocalFree __msabi; | ||||
| extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi; | ||||
| extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile __msabi; | ||||
| extern typeof(FlushViewOfFile) *const __imp_FlushViewOfFile __msabi; | ||||
| extern typeof(MapViewOfFileExNuma) *const __imp_MapViewOfFileExNuma __msabi; | ||||
| extern typeof(CreateFileMappingNuma) *const | ||||
|     __imp_CreateFileMappingNumaW __msabi; | ||||
|  |  | |||
|  | @ -22,20 +22,27 @@ | |||
| #include "libc/calls/internal.h" | ||||
| #include "libc/calls/ntspawn.h" | ||||
| #include "libc/calls/strace.internal.h" | ||||
| #include "libc/dce.h" | ||||
| #include "libc/fmt/itoa.h" | ||||
| #include "libc/intrin/kprintf.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/mem/alloca.h" | ||||
| #include "libc/nexgen32e/nt2sysv.h" | ||||
| #include "libc/nt/dll.h" | ||||
| #include "libc/nt/enum/exceptionhandleractions.h" | ||||
| #include "libc/nt/enum/filemapflags.h" | ||||
| #include "libc/nt/enum/memflags.h" | ||||
| #include "libc/nt/enum/pageflags.h" | ||||
| #include "libc/nt/enum/startf.h" | ||||
| #include "libc/nt/enum/wt.h" | ||||
| #include "libc/nt/files.h" | ||||
| #include "libc/nt/ipc.h" | ||||
| #include "libc/nt/memory.h" | ||||
| #include "libc/nt/process.h" | ||||
| #include "libc/nt/runtime.h" | ||||
| #include "libc/nt/signals.h" | ||||
| #include "libc/nt/struct/context.h" | ||||
| #include "libc/nt/struct/ntexceptionpointers.h" | ||||
| #include "libc/nt/synchronization.h" | ||||
| #include "libc/nt/thread.h" | ||||
| #include "libc/runtime/directmap.internal.h" | ||||
|  | @ -49,7 +56,14 @@ | |||
| #include "libc/sysv/consts/sig.h" | ||||
| #include "libc/sysv/errfuns.h" | ||||
| 
 | ||||
| static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) { | ||||
| extern int __pid; | ||||
| extern unsigned long long __kbirth; | ||||
| extern unsigned char __data_start[]; /* αpε */ | ||||
| extern unsigned char __data_end[];   /* αpε */ | ||||
| extern unsigned char __bss_start[];  /* αpε */ | ||||
| extern unsigned char __bss_end[];    /* αpε */ | ||||
| 
 | ||||
| static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) { | ||||
|   *x = 0; | ||||
|   while (*p == ' ') p++; | ||||
|   while ('0' <= *p && *p <= '9') { | ||||
|  | @ -59,89 +73,211 @@ static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) { | |||
|   return p; | ||||
| } | ||||
| 
 | ||||
| static dontinline textwindows noasan bool ForkIo(int64_t h, void *buf, size_t n, | ||||
| static inline textwindows ssize_t ForkIo(int64_t h, char *p, size_t n, | ||||
|                                          bool32 (*f)()) { | ||||
|   char *p; | ||||
|   size_t i; | ||||
|   uint32_t x; | ||||
|   for (p = buf, i = 0; i < n; i += x) { | ||||
|   for (i = 0; i < n; i += x) { | ||||
|     if (!f(h, p + i, n - i, &x, NULL)) { | ||||
|       return false; | ||||
|       return -1; | ||||
|     } | ||||
|   } | ||||
|   return true; | ||||
|   return i; | ||||
| } | ||||
| 
 | ||||
| static dontinline textwindows noasan void WriteAll(int64_t h, void *buf, | ||||
|                                                    size_t n) { | ||||
|   bool rc = ForkIo(h, buf, n, WriteFile); | ||||
|   STRACE("%s(%ld, %'zu) %d% m", "WriteFile", h, n); | ||||
| static dontinline textwindows bool ForkIo2(int64_t h, void *buf, size_t n, | ||||
|                                            bool32 (*fn)(), const char *sf) { | ||||
|   ssize_t rc = ForkIo(h, buf, n, fn); | ||||
|   STRACE("%s(%ld, %'zu) → %'zd% m", sf, h, n, rc); | ||||
|   return rc != -1; | ||||
| } | ||||
| 
 | ||||
| static textwindows dontinline noasan void ReadAll(int64_t h, void *buf, | ||||
|                                                   size_t n) { | ||||
|   bool rc = ForkIo(h, buf, n, ReadFile); | ||||
|   STRACE("%s(%ld, %'zu) %d% m", "ReadFile", h, n); | ||||
| static dontinline textwindows bool WriteAll(int64_t h, void *buf, size_t n) { | ||||
|   return ForkIo2(h, buf, n, WriteFile, "WriteFile"); | ||||
| } | ||||
| 
 | ||||
| textwindows noasan noinstrument void WinMainForked(void) { | ||||
|   void *addr; | ||||
| static textwindows dontinline bool ReadAll(int64_t h, void *buf, size_t n) { | ||||
|   return ForkIo2(h, buf, n, ReadFile, "ReadFile"); | ||||
| } | ||||
| 
 | ||||
| static textwindows int OnForkCrash(struct NtExceptionPointers *ep) { | ||||
|   kprintf("error: fork() child crashed!%n" | ||||
|           "\tExceptionCode = %#x%n" | ||||
|           "\tRip = %x%n" | ||||
|           "\tRax = %.16x  R8  = %.16x%n" | ||||
|           "\tRbx = %.16x  R9  = %.16x%n" | ||||
|           "\tRcx = %.16x  R10 = %.16x%n" | ||||
|           "\tRdx = %.16x  R11 = %.16x%n" | ||||
|           "\tRdi = %.16x  R12 = %.16x%n" | ||||
|           "\tRsi = %.16x  R13 = %.16x%n" | ||||
|           "\tRbp = %.16x  R14 = %.16x%n" | ||||
|           "\tRsp = %.16x  R15 = %.16x%n", | ||||
|           ep->ExceptionRecord->ExceptionCode, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rip : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rax : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->R8 : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rbx : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->R9 : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rcx : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->R10 : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rdx : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->R11 : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rdi : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->R12 : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rsi : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->R13 : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rbp : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->R14 : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->Rsp : -1, | ||||
|           ep->ContextRecord ? ep->ContextRecord->R15 : -1); | ||||
|   ExitProcess(73); | ||||
| } | ||||
| 
 | ||||
| textwindows void WinMainForked(void) { | ||||
|   jmp_buf jb; | ||||
|   long mapcount; | ||||
|   uint64_t size; | ||||
|   uint32_t i, varlen; | ||||
|   char *addr, *shad; | ||||
|   struct DirectMap dm; | ||||
|   uint64_t size, upsize; | ||||
|   int64_t reader, writer; | ||||
|   struct MemoryInterval *maps; | ||||
|   char16_t var[21 + 1 + 21 + 1]; | ||||
|   varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var)); | ||||
|   if (!varlen) return; | ||||
|   if (varlen >= ARRAYLEN(var)) ExitProcess(123); | ||||
|   char16_t fvar[21 + 1 + 21 + 1]; | ||||
|   int64_t oncrash, savetsc, savebir; | ||||
|   uint32_t i, varlen, oldprot, savepid; | ||||
|   long mapcount, mapcapacity, specialz; | ||||
|   extern uint64_t ts asm("kStartTsc"); | ||||
| 
 | ||||
|   /*
 | ||||
|    * check to see if the process was actually forked | ||||
|    * this variable should have the pipe handle numba | ||||
|    */ | ||||
|   varlen = GetEnvironmentVariable(u"_FORK", fvar, ARRAYLEN(fvar)); | ||||
|   if (!varlen || varlen >= ARRAYLEN(fvar)) return; | ||||
|   STRACE("WinMainForked()"); | ||||
|   SetEnvironmentVariable(u"_FORK", NULL); | ||||
|   ParseInt(ParseInt(var, &reader), &writer); | ||||
| #ifdef SYSDEBUG | ||||
|   oncrash = AddVectoredExceptionHandler(1, NT2SYSV(OnForkCrash)); | ||||
| #endif | ||||
|   ParseInt(ParseInt(fvar, &reader), &writer); | ||||
| 
 | ||||
|   /*
 | ||||
|    * read the cpu state from the parent process | ||||
|    */ | ||||
|   ReadAll(reader, jb, sizeof(jb)); | ||||
| 
 | ||||
|   /*
 | ||||
|    * read the list of mappings from the parent process | ||||
|    * this is stored in a special secretive memory map! | ||||
|    * read ExtendMemoryIntervals for further details :| | ||||
|    */ | ||||
|   maps = (void *)kMemtrackStart; | ||||
|   ReadAll(reader, &mapcount, sizeof(_mmi.i)); | ||||
|   maps = GlobalAlloc(0, mapcount * sizeof(*_mmi.p)); | ||||
|   ReadAll(reader, maps, mapcount * sizeof(*_mmi.p)); | ||||
|   ReadAll(reader, &mapcapacity, sizeof(_mmi.n)); | ||||
|   specialz = ROUNDUP(mapcapacity * sizeof(_mmi.p[0]), kMemtrackGran); | ||||
|   MapViewOfFileExNuma(CreateFileMappingNuma( | ||||
|                           -1, &kNtIsInheritable, kNtPageReadwrite, | ||||
|                           specialz >> 32, specialz, 0, kNtNumaNoPreferredNode), | ||||
|                       kNtFileMapWrite, 0, 0, specialz, maps, | ||||
|                       kNtNumaNoPreferredNode); | ||||
|   ReadAll(reader, maps, mapcount * sizeof(_mmi.p[0])); | ||||
|   if (IsAsan()) { | ||||
|     shad = (char *)(((intptr_t)maps >> 3) + 0x7fff8000); | ||||
|     size = ROUNDUP(specialz >> 3, FRAMESIZE); | ||||
|     MapViewOfFileExNuma( | ||||
|         CreateFileMappingNuma(-1, &kNtIsInheritable, kNtPageReadwrite, | ||||
|                               size >> 32, size, 0, kNtNumaNoPreferredNode), | ||||
|         kNtFileMapWrite, 0, 0, size, maps, kNtNumaNoPreferredNode); | ||||
| #if 0 | ||||
|     ReadAll(reader, shad, (mapcount * sizeof(_mmi.p[0])) >> 3); | ||||
| #endif | ||||
|   } | ||||
| 
 | ||||
|   /*
 | ||||
|    * read the heap mappings from the parent process | ||||
|    * we can avoid copying via pipe for shared maps! | ||||
|    */ | ||||
|   for (i = 0; i < mapcount; ++i) { | ||||
|     addr = (void *)((uint64_t)maps[i].x << 16); | ||||
|     size = ((uint64_t)(maps[i].y - maps[i].x) << 16) + FRAMESIZE; | ||||
|     addr = (char *)((uint64_t)maps[i].x << 16); | ||||
|     size = maps[i].size; | ||||
|     if (maps[i].flags & MAP_PRIVATE) { | ||||
|       CloseHandle(maps[i].h); | ||||
|       maps[i].h = | ||||
|           sys_mmap_nt(addr, size, maps[i].prot, maps[i].flags, -1, 0).maphandle; | ||||
|       STRACE("fork() child %p %'zu copying private map", addr, size); | ||||
|       if (!CloseHandle(maps[i].h)) { | ||||
|         STRACE("fork() child CloseHandle(%ld) ~~~FAILED~~~ %m", maps[i].h); | ||||
|       } | ||||
|       upsize = ROUNDUP(size, FRAMESIZE); | ||||
|       maps[i].h = CreateFileMappingNuma(-1, &kNtIsInheritable, | ||||
|                                         kNtPageExecuteReadwrite, upsize >> 32, | ||||
|                                         upsize, NULL, kNtNumaNoPreferredNode); | ||||
|       MapViewOfFileExNuma(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0, | ||||
|                           upsize, addr, kNtNumaNoPreferredNode); | ||||
|       ReadAll(reader, addr, size); | ||||
|     } else { | ||||
|       MapViewOfFileExNuma( | ||||
|           maps[i].h, | ||||
|       STRACE("fork() child %p %'zu mapping shared hand:%ld offset:%'lu", addr, | ||||
|              size, maps[i].h, maps[i].offset); | ||||
|       MapViewOfFileExNuma(maps[i].h, | ||||
|                           (maps[i].prot & PROT_WRITE) | ||||
|               ? kNtFileMapWrite | kNtFileMapExecute | kNtFileMapRead | ||||
|               : kNtFileMapExecute | kNtFileMapRead, | ||||
|           0, 0, size, addr, kNtNumaNoPreferredNode); | ||||
|                               ? kNtFileMapWrite | kNtFileMapExecute | ||||
|                               : kNtFileMapRead | kNtFileMapExecute, | ||||
|                           maps[i].offset >> 32, maps[i].offset, size, addr, | ||||
|                           kNtNumaNoPreferredNode); | ||||
|     } | ||||
|   } | ||||
|   ReadAll(reader, _etext, _end - _etext); | ||||
| 
 | ||||
|   /*
 | ||||
|    * read the .data and .bss program image sections | ||||
|    */ | ||||
|   savepid = __pid; | ||||
|   savebir = __kbirth; | ||||
|   savetsc = ts; | ||||
|   STRACE("fork() child reading %'zu bytes of .data to %p", | ||||
|          __data_end - __data_start, __data_start); | ||||
|   ReadAll(reader, __data_start, __data_end - __data_start); | ||||
|   STRACE("fork() child reading %'zu bytes of .bss to %p", | ||||
|          __bss_end - __bss_start, __bss_start); | ||||
|   ReadAll(reader, __bss_start, __bss_end - __bss_start); | ||||
|   __pid = savepid; | ||||
|   __kbirth = savebir; | ||||
|   ts = savetsc; | ||||
| 
 | ||||
|   /*
 | ||||
|    * apply fixups and reapply memory protections | ||||
|    */ | ||||
|   STRACE("fork() child applying fixups to _mmi.p"); | ||||
|   _mmi.p = maps; | ||||
|   _mmi.n = specialz / sizeof(_mmi.p[0]); | ||||
|   for (i = 0; i < mapcount; ++i) { | ||||
|     _mmi.p[i].h = maps[i].h; | ||||
|     if ((maps[i].flags & MAP_PRIVATE) && (~maps[i].prot & PROT_WRITE)) { | ||||
|       VirtualProtect((void *)((uint64_t)maps[i].x << 16), | ||||
|                      ROUNDUP(maps[i].size, FRAMESIZE), | ||||
|                      __prot2nt(maps[i].prot, 0), &oldprot); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /*
 | ||||
|    * clean up and restore old processor state | ||||
|    */ | ||||
|   STRACE("fork() child almost done!"); | ||||
|   CloseHandle(reader); | ||||
|   CloseHandle(writer); | ||||
|   GlobalFree(maps); | ||||
| #ifdef SYSDEBUG | ||||
|   RemoveVectoredExceptionHandler(oncrash); | ||||
| #endif | ||||
|   if (weaken(__wincrash_nt)) { | ||||
|     AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt)); | ||||
|   } | ||||
|   STRACE("fork() child it's time for the big jump (>'.')>"); | ||||
|   longjmp(jb, 1); | ||||
| } | ||||
| 
 | ||||
| textwindows int sys_fork_nt(void) { | ||||
|   bool ok; | ||||
|   jmp_buf jb; | ||||
|   char **args, **args2; | ||||
|   int64_t reader, writer; | ||||
|   int i, rc, pid, releaseme; | ||||
|   int i, n, rc, pid, untrackpid; | ||||
|   char *p, forkvar[6 + 21 + 1 + 21 + 1]; | ||||
|   struct NtStartupInfo startinfo; | ||||
|   struct NtProcessInformation procinfo; | ||||
|   if ((pid = releaseme = __reservefd()) == -1) return -1; | ||||
|   if ((pid = untrackpid = __reservefd()) == -1) return -1; | ||||
|   if (!setjmp(jb)) { | ||||
|     if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) { | ||||
|       p = stpcpy(forkvar, "_FORK="); | ||||
|  | @ -153,43 +289,94 @@ textwindows int sys_fork_nt(void) { | |||
|       startinfo.hStdInput = g_fds.p[0].handle; | ||||
|       startinfo.hStdOutput = g_fds.p[1].handle; | ||||
|       startinfo.hStdError = g_fds.p[2].handle; | ||||
|       if (ntspawn(program_executable_name, __argv, environ, forkvar, | ||||
|       args = __argv; | ||||
| #ifdef SYSDEBUG | ||||
|       /*
 | ||||
|        * If --strace was passed to this program, then propagate it the | ||||
|        * forked process since the flag was removed by __intercept_flag | ||||
|        */ | ||||
|       if (__strace > 0) { | ||||
|         for (n = 0; args[n];) ++n; | ||||
|         args2 = alloca((n + 2) * sizeof(char *)); | ||||
|         for (i = 0; i < n; ++i) args2[i] = args[i]; | ||||
|         args2[i++] = "--strace"; | ||||
|         args2[i] = 0; | ||||
|         args = args2; | ||||
|       } | ||||
| #endif | ||||
|       if (ntspawn(program_executable_name, args, environ, forkvar, | ||||
|                   &kNtIsInheritable, NULL, true, 0, NULL, &startinfo, | ||||
|                   &procinfo) != -1) { | ||||
|         CloseHandle(reader); | ||||
|         CloseHandle(procinfo.hThread); | ||||
|         if (weaken(__sighandrvas) && | ||||
|             weaken(__sighandrvas)[SIGCHLD] == SIG_IGN) { | ||||
|           CloseHandle(procinfo.hProcess); | ||||
|         } else { | ||||
|         ok = WriteAll(writer, jb, sizeof(jb)) && | ||||
|              WriteAll(writer, &_mmi.i, sizeof(_mmi.i)) && | ||||
|              WriteAll(writer, &_mmi.n, sizeof(_mmi.n)) && | ||||
|              WriteAll(writer, _mmi.p, _mmi.i * sizeof(_mmi.p[0])); | ||||
| #if 0 | ||||
|         if (IsAsan() && ok) { | ||||
|           ok = WriteAll(writer, (char *)(((intptr_t)_mmi.p >> 3) + 0x7fff8000), | ||||
|                         (_mmi.i * sizeof(_mmi.p[0])) >> 3); | ||||
|         } | ||||
| #endif | ||||
|         for (i = 0; i < _mmi.i && ok; ++i) { | ||||
|           if (_mmi.p[i].flags & MAP_PRIVATE) { | ||||
|             ok = WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16), | ||||
|                           _mmi.p[i].size); | ||||
|           } | ||||
|         } | ||||
|         if (ok) { | ||||
|           STRACE("fork() parent writing %'zu bytes of .data", | ||||
|                  __data_end - __data_start); | ||||
|           ok = WriteAll(writer, __data_start, __data_end - __data_start); | ||||
|         } | ||||
|         if (ok) { | ||||
|           STRACE("fork() parent writing %'zu bytes of .bss", | ||||
|                  __bss_end - __bss_start); | ||||
|           ok = WriteAll(writer, __bss_start, __bss_end - __bss_start); | ||||
|         } | ||||
|         ok = ok & !!CloseHandle(writer); | ||||
|         if (ok) { | ||||
|           if (!weaken(__sighandrvas) || | ||||
|               weaken(__sighandrvas)[SIGCHLD] != SIG_IGN) { | ||||
|             g_fds.p[pid].kind = kFdProcess; | ||||
|             g_fds.p[pid].handle = procinfo.hProcess; | ||||
|             g_fds.p[pid].flags = O_CLOEXEC; | ||||
|           releaseme = -1; | ||||
|         } | ||||
|         WriteAll(writer, jb, sizeof(jb)); | ||||
|         WriteAll(writer, &_mmi.i, sizeof(_mmi.i)); | ||||
|         WriteAll(writer, _mmi.p, _mmi.i * sizeof(*_mmi.p)); | ||||
|         for (i = 0; i < _mmi.i; ++i) { | ||||
|           if (_mmi.p[i].flags & MAP_PRIVATE) { | ||||
|             WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16), | ||||
|                      ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE); | ||||
|           } | ||||
|         } | ||||
|         WriteAll(writer, _etext, _end - _etext); | ||||
|         CloseHandle(writer); | ||||
|             untrackpid = -1; | ||||
|           } else { | ||||
|         rc = -1; | ||||
|             /*
 | ||||
|              * XXX: Ignoring SIGCHLD should track the process information. | ||||
|              *      What we need to do instead, is periodically check if a | ||||
|              *      process has exited and remove it automatically via i/o | ||||
|              *      functions like poll() so it doesn't get zombdied. | ||||
|              */ | ||||
|             STRACE("fork() parent closing process handle b/c SIGCHLD=SIG_IGN"); | ||||
|             CloseHandle(procinfo.hProcess); | ||||
|           } | ||||
|           STRACE("fork() parent everything looks good"); | ||||
|           rc = pid; | ||||
|         } else { | ||||
|           STRACE("fork() parent ~~failed~~ because writing failed"); | ||||
|           rc = __winerr(); | ||||
|           TerminateProcess(procinfo.hProcess, 127); | ||||
|           CloseHandle(procinfo.hProcess); | ||||
|         } | ||||
|       } else { | ||||
|         STRACE("fork() parent ~~failed~~ because ntspawn failed"); | ||||
|         CloseHandle(writer); | ||||
|         rc = -1; | ||||
|       } | ||||
|     } else { | ||||
|       STRACE("fork() parent ~~failed~~ because CreatePipe() failed %m"); | ||||
|       rc = __winerr(); | ||||
|       CloseHandle(writer); | ||||
|     } | ||||
|   } else { | ||||
|     STRACE("fork() child welcome back <('.'<)"); | ||||
|     rc = 0; | ||||
|   } | ||||
|   if (releaseme != -1) { | ||||
|     __releasefd(releaseme); | ||||
|   if (untrackpid != -1) { | ||||
|     __releasefd(untrackpid); | ||||
|   } | ||||
|   return rc; | ||||
| } | ||||
|  |  | |||
|  | @ -71,6 +71,7 @@ static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) { | |||
|   base = (char *)kMemtrackStart; | ||||
|   prot = PROT_READ | PROT_WRITE; | ||||
|   flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED; | ||||
|   /* TODO(jart): These map handles should not leak across NT fork() */ | ||||
|   if (mm->p == mm->s) { | ||||
|     if (IsAsan()) { | ||||
|       shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000); | ||||
|  | @ -170,7 +171,7 @@ noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, | |||
| } | ||||
| 
 | ||||
| noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, | ||||
|                                int prot, int flags) { | ||||
|                                int prot, int flags, long offset, long size) { | ||||
|   /* asan runtime depends on this function */ | ||||
|   unsigned i; | ||||
|   assert(y >= x); | ||||
|  | @ -194,6 +195,8 @@ noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, | |||
|     mm->p[i].h = h; | ||||
|     mm->p[i].prot = prot; | ||||
|     mm->p[i].flags = flags; | ||||
|     mm->p[i].offset = offset; | ||||
|     mm->p[i].size = size; | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -15,8 +15,10 @@ COSMOPOLITAN_C_START_ | |||
|   _kMem(0x200000000000 - 0x100080000000 - _kMmi(0x800000000000), \ | ||||
|         0x000040000000 - 0x000010000000 - _kMmi(0x000080000000)) | ||||
| #define kMemtrackStart                                      \ | ||||
|   _kMem(0x200000000000 - _kMmi(0x800000000000), \ | ||||
|         0x000040000000 - _kMmi(0x000080000000)) | ||||
|   (ROUNDDOWN(_kMem(0x200000000000 - _kMmi(0x800000000000),  \ | ||||
|                    0x000040000000 - _kMmi(0x000080000000)), \ | ||||
|              FRAMESIZE * 8) -                               \ | ||||
|    0x8000 * 8 /* so frame aligned after adding 0x7fff8000 */) | ||||
| #define kMemtrackSize  _kMem(_kMmi(0x800000000000), _kMmi(0x000080000000)) | ||||
| #define kMemtrackGran  (!IsAsan() ? FRAMESIZE : FRAMESIZE * 8) | ||||
| #define kFixedmapStart _kMem(0x300000000000, 0x000040000000) | ||||
|  | @ -34,6 +36,8 @@ struct MemoryInterval { | |||
|   long h; | ||||
|   int prot; | ||||
|   int flags; | ||||
|   long offset; | ||||
|   long size; | ||||
| }; | ||||
| 
 | ||||
| struct MemoryIntervals { | ||||
|  | @ -50,8 +54,8 @@ char *DescribeProt(int, char[hasatleast 4]); | |||
| char *DescribeMapping(int, int, char[hasatleast 8]) hidden; | ||||
| bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden; | ||||
| void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden; | ||||
| int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, | ||||
|                         int) hidden; | ||||
| int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int, | ||||
|                         long, long) hidden; | ||||
| int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int, | ||||
|                            void (*)(struct MemoryIntervals *, int, int)) hidden; | ||||
| void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden; | ||||
|  |  | |||
|  | @ -128,7 +128,8 @@ static noasan void *MapMemory(void *addr, size_t size, int prot, int flags, | |||
|       Die(); | ||||
|     } | ||||
|   } | ||||
|   if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags)) { | ||||
|   if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags, off, | ||||
|                           size)) { | ||||
|     if (sys_munmap(addr, n) == -1) { | ||||
|       STRACE("TRACK MUNMAP FAILED %m"); | ||||
|       assert(!"MapMemory() failed"); | ||||
|  | @ -152,26 +153,31 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size, | |||
|                                                        int prot, int flags, | ||||
|                                                        int fd, int64_t off, | ||||
|                                                        int f, int x, size_t n) { | ||||
|   int64_t oi, sz; | ||||
|   struct DirectMap dm; | ||||
|   size_t i, m = (n - 1) * FRAMESIZE; | ||||
|   assert(m < size && m + FRAMESIZE >= size); | ||||
|   dm = sys_mmap(addr + m, size - m, prot, f, fd, fd == -1 ? 0 : off + m); | ||||
|   oi = fd == -1 ? 0 : off + m; | ||||
|   sz = size - m; | ||||
|   dm = sys_mmap(addr + m, sz, prot, f, fd, oi); | ||||
|   if (dm.addr == MAP_FAILED) { | ||||
|     STRACE("MapMemories(%.12p+%lx/%lx) %m", addr, m, size); | ||||
|     return MAP_FAILED; | ||||
|   } | ||||
|   if (TrackMemoryInterval(&_mmi, x + (n - 1), x + (n - 1), dm.maphandle, prot, | ||||
|                           flags) == -1) { | ||||
|                           flags, oi, sz) == -1) { | ||||
|     STRACE("MapMemories(%.12p+%lx/%lx) unrecoverable failure #1 %m", addr, m, | ||||
|            size); | ||||
|     assert(!"MapMemories() failed"); | ||||
|     Die(); | ||||
|   } | ||||
|   for (i = 0; i < m; i += FRAMESIZE) { | ||||
|     dm = sys_mmap(addr + i, FRAMESIZE, prot, f, fd, fd == -1 ? 0 : off + i); | ||||
|     oi = fd == -1 ? 0 : off + i; | ||||
|     sz = FRAMESIZE; | ||||
|     dm = sys_mmap(addr + i, sz, prot, f, fd, oi); | ||||
|     if (dm.addr == MAP_FAILED || | ||||
|         TrackMemoryInterval(&_mmi, x + i / FRAMESIZE, x + i / FRAMESIZE, | ||||
|                             dm.maphandle, prot, flags) == -1) { | ||||
|                             dm.maphandle, prot, flags, oi, sz) == -1) { | ||||
|       STRACE("MapMemories(%p+%x/%x) unrecoverable failure #2 %m", addr, i, | ||||
|              size); | ||||
|       assert(!"MapMemories() failed"); | ||||
|  |  | |||
|  | @ -145,7 +145,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { | |||
|     if (dm.addr == MAP_FAILED) return 0; | ||||
|     if (TrackMemoryInterval(&_mmi, ((uintptr_t)p + n) >> 16, | ||||
|                             ((uintptr_t)p + m - FRAMESIZE) >> 16, dm.maphandle, | ||||
|                             prot, flags) != -1) { | ||||
|                             prot, flags, 0, m - n) != -1) { | ||||
|       if (weaken(__asan_map_shadow)) { | ||||
|         weaken(__asan_map_shadow)((uintptr_t)dm.addr, m - n); | ||||
|       } | ||||
|  | @ -178,7 +178,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { | |||
|     if (q == MAP_FAILED) return 0; | ||||
|     if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16, | ||||
|                                ((uintptr_t)p + n - FRAMESIZE) >> 16, 0) != -1 && | ||||
|         TrackMemoryInterval(&_mmi, a, b, -1, prot, flags) != -1) { | ||||
|         TrackMemoryInterval(&_mmi, a, b, -1, prot, flags, 0, m) != -1) { | ||||
|       if (weaken(__asan_poison)) { | ||||
|         if (!OverlapsShadowSpace(p, n)) { | ||||
|           weaken(__asan_poison)((intptr_t)p, n, kAsanUnmapped); | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ extern unsigned char _base[] forcealign(PAGESIZE);  /* αpε */ | |||
| extern unsigned char _ehead[] forcealign(PAGESIZE); /* αpε */ | ||||
| extern unsigned char _etext[] forcealign(PAGESIZE); /* αpε */ | ||||
| extern unsigned char _edata[] forcealign(PAGESIZE); /* αpε */ | ||||
| extern unsigned char _ezip[];                       /* αpε */ | ||||
| extern unsigned char _end[] forcealign(FRAMESIZE);  /* αpε */ | ||||
| extern unsigned char _ereal;                        /* αpε */ | ||||
| extern unsigned char __privileged_start;            /* αpε */ | ||||
|  |  | |||
|  | @ -59,6 +59,7 @@ $(LIBC_RUNTIME_A).pkg:					\ | |||
| 
 | ||||
| o/$(MODE)/libc/runtime/printf.o				\ | ||||
| o/$(MODE)/libc/runtime/abort-nt.o			\ | ||||
| o/$(MODE)/libc/runtime/printmemoryintervals.o		\ | ||||
| o/$(MODE)/libc/runtime/arememoryintervalsok.o		\ | ||||
| o/$(MODE)/libc/runtime/assertfail.o			\ | ||||
| o/$(MODE)/libc/runtime/directmap.o			\ | ||||
|  | @ -81,6 +82,15 @@ o/$(MODE)/libc/runtime/winmain.greg.o:			\ | |||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			$(NO_MAGIC) | ||||
| 
 | ||||
| # must use alloca()
 | ||||
| # can't use asan or any runtime services
 | ||||
| o/$(MODE)/libc/runtime/fork-nt.o:			\ | ||||
| 		OVERRIDE_CPPFLAGS +=			\
 | ||||
| 			-DSTACK_FRAME_UNLIMITED | ||||
| o/$(MODE)/libc/runtime/fork-nt.o:			\ | ||||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			$(NO_MAGIC) | ||||
| 
 | ||||
| o/$(MODE)/libc/runtime/printf.o				\ | ||||
| o/$(MODE)/libc/runtime/memtrack.o			\ | ||||
| o/$(MODE)/libc/runtime/mman.greg.o:			\ | ||||
|  |  | |||
|  | @ -72,6 +72,7 @@ struct WinArgs { | |||
| 
 | ||||
| extern int __pid; | ||||
| extern bool __nomultics; | ||||
| extern uint32_t __winmainpid; | ||||
| extern const char kConsoleHandles[2]; | ||||
| 
 | ||||
| static const short kConsoleModes[2] = { | ||||
|  | @ -115,6 +116,7 @@ static noasan textwindows wontreturn noinstrument void WinMainNew( | |||
|   version = NtGetPeb()->OSMajorVersion; | ||||
|   __oldstack = (intptr_t)__builtin_frame_address(0); | ||||
|   if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) { | ||||
|     __winmainpid = __pid; | ||||
|     rc = SetConsoleCP(kNtCpUtf8); | ||||
|     STRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc); | ||||
|     rc = SetConsoleOutputCP(kNtCpUtf8); | ||||
|  | @ -147,6 +149,7 @@ static noasan textwindows wontreturn noinstrument void WinMainNew( | |||
|   _mmi.p[0].y = (allocaddr >> 16) + ((allocsize >> 16) - 1); | ||||
|   _mmi.p[0].prot = PROT_READ | PROT_WRITE | PROT_EXEC; | ||||
|   _mmi.p[0].flags = MAP_PRIVATE | MAP_ANONYMOUS; | ||||
|   _mmi.p[0].size = allocsize; | ||||
|   _mmi.i = 1; | ||||
|   wa = (struct WinArgs *)allocaddr; | ||||
|   STRACE("WinMainNew() loading arg block"); | ||||
|  |  | |||
|  | @ -16,8 +16,10 @@ | |||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/bits/weaken.h" | ||||
| #include "libc/calls/strace.internal.h" | ||||
| #include "libc/dce.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/nt/runtime.h" | ||||
| #include "libc/nt/winsock.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
|  | @ -35,7 +37,17 @@ | |||
| hidden struct NtWsaData kNtWsaData; | ||||
| 
 | ||||
| static textwindows void WinSockCleanup(void) { | ||||
|   size_t i; | ||||
|   STRACE("WSACleanup()"); | ||||
|   WSACleanup(); | ||||
|   for (i = 0; i < g_fds.n; ++i) { | ||||
|     if (g_fds.p[i].kind == kFdSocket) { | ||||
|       if (weaken(free)) { | ||||
|         weaken(free)((struct SockFd *)g_fds.p[i].extra); | ||||
|         g_fds.p[i].extra = 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| textwindows noasan void WinSockInit(void) { | ||||
|  |  | |||
|  | @ -74,7 +74,7 @@ void longsort(long *x, size_t n) { | |||
|   } | ||||
|   if (n > 1) { | ||||
|     t = 1ul << bsrl(n - 1); | ||||
|     if (X86_HAVE(AVX2)) { | ||||
|     if (!IsTiny() && X86_HAVE(AVX2)) { | ||||
|       longsort_avx2(x, n, t); | ||||
|     } else { | ||||
|       longsort_pure(x, n, t); | ||||
|  |  | |||
|  | @ -35,6 +35,10 @@ | |||
| 	__ro = 0 | ||||
| 	__relo_start = 0 | ||||
| 	__relo_end = 0 | ||||
| 	__data_start = 0 | ||||
| 	__data_end = 0 | ||||
| 	__bss_start = 0 | ||||
| 	__bss_end = 0 | ||||
| 
 | ||||
| //	Thread local boundaries defined by linker script | ||||
| //	@see	ape/ape.lds
 | ||||
|  | @ -59,6 +63,10 @@ | |||
| 	.globl	_tbss_end
 | ||||
| 	.globl	_tdata_start
 | ||||
| 	.globl	_tdata_end
 | ||||
| 	.globl	__data_start
 | ||||
| 	.globl	__data_end
 | ||||
| 	.globl	__bss_start
 | ||||
| 	.globl	__bss_end
 | ||||
| 
 | ||||
| 	.weak	_base
 | ||||
| 	.weak	ape_xlm
 | ||||
|  | @ -76,3 +84,7 @@ | |||
| 	.weak	_tbss_end
 | ||||
| 	.weak	_tdata_start
 | ||||
| 	.weak	_tdata_end
 | ||||
| 	.weak	__data_start
 | ||||
| 	.weak	__data_end
 | ||||
| 	.weak	__bss_start
 | ||||
| 	.weak	__bss_end
 | ||||
|  |  | |||
|  | @ -175,30 +175,28 @@ syscon	compat	SIGPOLL					29			23			23			23			23			29			# same as SIGIO | |||
| syscon	compat	SIGIOT					6			6			6			6			6			6			# PDP-11 feature; same as SIGABRT | ||||
| syscon	compat	SIGPWR					30			30			30			30			32			30			# not implemented in most community editions of system five; consider doing this using SIGUSR1 or SIGUSR2 instead | ||||
| 
 | ||||
| #	open() flags																				       ┌──────hoo boy | ||||
| #																						   ┌──────┐ | ||||
| #																						   │┌─<<8─┴───dwFlagsAndAttributes | ||||
| #																						  ┌││─────┐ | ||||
| #																						  │││  │ ┌┴───dwDesiredAccess | ||||
| #																						N │││  │ │ | ||||
| #	group	name					GNU/Systemd		XNU's Not UNIX!		FreeBSD			OpenBSD			NetBSD			T │││┌─┴┐│		Commentary | ||||
| syscon	open	O_RDONLY				0			0			0			0			0			0xA0000000		# unix consensus & kNtGenericRead|kNtGenericExecute | ||||
| syscon	open	O_WRONLY				1			1			1			1			1			0x40000000		# unix consensus & kNtGenericWrite | ||||
| syscon	open	O_RDWR					2			2			2			2			2			0xE0000000		# unix consensus & kNtGenericRead|kNtGenericWrite|kNtGenericExecute | ||||
| syscon	open	O_ACCMODE				3			3			3			3			3			0xE0000000		# O_RDONLY|O_WRONLY|O_RDWR | ||||
| syscon	open	O_APPEND				0x00000400		8			8			8			8			0x00000004		# bsd consensus & kNtFileAppendData; won't pose issues w/ mknod(S_IFIFO) | ||||
| syscon	open	O_CREAT					0x00000040		0x00000200		0x00000200		0x00000200		0x00000200		0x00000040		# bsd consensus & NT faked as Linux | ||||
| syscon	open	O_EXCL					0x00000080		0x00000800		0x00000800		0x00000800		0x00000800		0x00000080		# bsd consensus & NT faked as Linux | ||||
| syscon	open	O_TRUNC					0x00000200		0x00000400		0x00000400		0x00000400		0x00000400		0x00000200		# bsd consensus & NT faked as Linux | ||||
| syscon	open	O_DIRECTORY				0x00010000		0x00100000		0x00020000		0x00020000		0x00200000		0x02000000		# useful hint on UNIX, but required on NT (see kNtFileFlagBackupSemantics) | ||||
| syscon	open	O_RANDOM				0			0			0			0			0			0x10000000		# kNtFileFlagRandomAccess | ||||
| syscon	open	O_SEQUENTIAL				0			0			0			0			0			0x08000000		# kNtFileFlagSequentialScan | ||||
| syscon	open	O_DIRECT				0x00004000		0			0x00010000		0			0x00080000		0x00200000		# kNtFileFlagNoBuffering>>8 | ||||
| syscon	open	O_CLOEXEC				0x00080000		0x01000000		0x00100000		0x00010000		0x00400000		0x00080000		# NT faked as Linux | ||||
| syscon	open	O_TMPFILE				0x00410000		0			0			0			0			0x00000000		# Linux 3.11+ (c. 2013) & kNtFileAttributeTemporary|kNtFileFlagDeleteOnClose | ||||
| syscon	open	O_SPARSE				0			0			0			0			0			0x00040000		# we invented it | ||||
| syscon	open	O_NDELAY				0x00000800		0x00000004		0x00000004		0x00000004		0x00000004		0x00000800		# bsd consensus & kNtFileFlagWriteThrough>>8 → 0x00800000 (???) | ||||
| syscon	open	O_NONBLOCK				0x00000800		0x00000004		0x00000004		0x00000004		0x00000004		0x00000800		# bsd consensus & faked on nt to be same as linux | ||||
| #	open() flags | ||||
| # | ||||
| #	group	name					GNU/Systemd		XNU's Not UNIX!		FreeBSD			OpenBSD			NetBSD			Windoze			Commentary | ||||
| syscon	open	O_RDONLY				0			0			0			0			0			0			# consensus | ||||
| syscon	open	O_WRONLY				1			1			1			1			1			1			# consensus | ||||
| syscon	open	O_RDWR					2			2			2			2			2			2			# consensus | ||||
| syscon	open	O_ACCMODE				3			3			3			3			3			3			# O_RDONLY|O_WRONLY|O_RDWR | ||||
| syscon	open	O_APPEND				0x00000400		8			8			8			8			0x00000400		# bsd consensus & kNtFileAppendData; won't pose issues w/ mknod(S_IFIFO) [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_CREAT					0x00000040		0x00000200		0x00000200		0x00000200		0x00000200		0x00000040		# bsd consensus & NT faked as Linux [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_EXCL					0x00000080		0x00000800		0x00000800		0x00000800		0x00000800		0x00000080		# bsd consensus & NT faked as Linux [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_TRUNC					0x00000200		0x00000400		0x00000400		0x00000400		0x00000400		0x00000200		# bsd consensus & NT faked as Linux [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_DIRECTORY				0x00010000		0x00100000		0x00020000		0x00020000		0x00200000		0x00010000		# useful hint on UNIX, but required on NT (see kNtFileFlagBackupSemantics) [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_DIRECT				0x00004000		0			0x00010000		0			0x00080000		0x00004000		#  kNtFileFlagNoBuffering [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_NDELAY				0x00000800		0x00000004		0x00000004		0x00000004		0x00000004		0x00000800		#  kNtFileFlagWriteThrough [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_RANDOM				0			0			0			0			0			0x80000000		#  kNtFileFlagRandomAccess [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_SEQUENTIAL				0			0			0			0			0			0x40000000		#  kNtFileFlagSequentialScan [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_COMPRESSED				0			0			0			0			0			0x20000000		#  kNtFileAttributeCompressed [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_INDEXED				0			0			0			0			0			0x10000000		# !kNtFileAttributeNotContentIndexed [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_CLOEXEC				0x00080000		0x01000000		0x00100000		0x00010000		0x00400000		0x00080000		# NT faked as Linux [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_TMPFILE				0x00410000		0			0			0			0			0x00410000		# Linux 3.11+ (c. 2013) & kNtFileAttributeTemporary|kNtFileFlagDeleteOnClose [SYNC libc/calls/open-nt.c] | ||||
| syscon	open	O_SPARSE				0			0			0			0			0			0			# wut | ||||
| syscon	open	O_NONBLOCK				0x00000800		0x00000004		0x00000004		0x00000004		0x00000004		0x00000800		# bsd consensus | ||||
| syscon	open	O_ASYNC					0x00002000		0x00000040		0x00000040		0x00000040		0x00000040		0			# bsd consensus | ||||
| syscon	open	O_NOFOLLOW				0x00020000		0x00000100		0x00000100		0x00000100		0x00000100		0			# bsd consensus | ||||
| syscon	open	O_NOFOLLOW_ANY				0			0x20000000		0			0			0			0			# | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_ACCMODE,3,3,3,3,3,0xE0000000 | ||||
| .syscon open,O_ACCMODE,3,3,3,3,3,3 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_APPEND,0x00000400,8,8,8,8,0x00000004 | ||||
| .syscon open,O_APPEND,0x00000400,8,8,8,8,0x00000400 | ||||
|  |  | |||
							
								
								
									
										2
									
								
								libc/sysv/consts/O_COMPRESSED.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								libc/sysv/consts/O_COMPRESSED.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_COMPRESSED,0,0,0,0,0,0x20000000 | ||||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_DIRECT,0x00004000,0,0x00010000,0,0x00080000,0x00200000 | ||||
| .syscon open,O_DIRECT,0x00004000,0,0x00010000,0,0x00080000,0x00004000 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_DIRECTORY,0x00010000,0x00100000,0x00020000,0x00020000,0x00200000,0x02000000 | ||||
| .syscon open,O_DIRECTORY,0x00010000,0x00100000,0x00020000,0x00020000,0x00200000,0x00010000 | ||||
|  |  | |||
							
								
								
									
										2
									
								
								libc/sysv/consts/O_INDEXED.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								libc/sysv/consts/O_INDEXED.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_INDEXED,0,0,0,0,0,0x10000000 | ||||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_RANDOM,0,0,0,0,0,0x10000000 | ||||
| .syscon open,O_RANDOM,0,0,0,0,0,0x80000000 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_RDONLY,0,0,0,0,0,0xA0000000 | ||||
| .syscon open,O_RDONLY,0,0,0,0,0,0 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_RDWR,2,2,2,2,2,0xE0000000 | ||||
| .syscon open,O_RDWR,2,2,2,2,2,2 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_SEQUENTIAL,0,0,0,0,0,0x08000000 | ||||
| .syscon open,O_SEQUENTIAL,0,0,0,0,0,0x40000000 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_SPARSE,0,0,0,0,0,0x00040000 | ||||
| .syscon open,O_SPARSE,0,0,0,0,0,0 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_TMPFILE,0x00410000,0,0,0,0,0x00000000 | ||||
| .syscon open,O_TMPFILE,0x00410000,0,0,0,0,0x00410000 | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| #include "libc/sysv/consts/syscon.internal.h" | ||||
| .syscon open,O_WRONLY,1,1,1,1,1,0x40000000 | ||||
| .syscon open,O_WRONLY,1,1,1,1,1,1 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ extern const unsigned O_ACCMODE; | |||
| extern const unsigned O_APPEND; | ||||
| extern const unsigned O_ASYNC; | ||||
| extern const unsigned O_CLOEXEC; | ||||
| extern const unsigned O_COMPRESSED; | ||||
| extern const unsigned O_CREAT; | ||||
| extern const unsigned O_DIRECT; | ||||
| extern const unsigned O_DIRECTORY; | ||||
|  | @ -15,6 +16,7 @@ extern const unsigned O_DSYNC; | |||
| extern const unsigned O_EXCL; | ||||
| extern const unsigned O_EXEC; | ||||
| extern const unsigned O_EXLOCK; | ||||
| extern const unsigned O_INDEXED; | ||||
| extern const unsigned O_LARGEFILE; | ||||
| extern const unsigned O_NDELAY; | ||||
| extern const unsigned O_NOATIME; | ||||
|  | @ -41,10 +43,15 @@ extern const unsigned O_WRONLY; | |||
| COSMOPOLITAN_C_END_ | ||||
| #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||||
| 
 | ||||
| #define O_ACCMODE      SYMBOLIC(O_ACCMODE) | ||||
| #define O_RDONLY  LITERALLY(0) | ||||
| #define O_WRONLY  LITERALLY(1) | ||||
| #define O_RDWR    LITERALLY(2) | ||||
| #define O_ACCMODE LITERALLY(3) | ||||
| 
 | ||||
| #define O_APPEND       SYMBOLIC(O_APPEND) | ||||
| #define O_ASYNC        SYMBOLIC(O_ASYNC) | ||||
| #define O_CLOEXEC      SYMBOLIC(O_CLOEXEC) | ||||
| #define O_COMPRESSED   SYMBOLIC(O_COMPRESSED) | ||||
| #define O_CREAT        SYMBOLIC(O_CREAT) | ||||
| #define O_DIRECT       SYMBOLIC(O_DIRECT) | ||||
| #define O_DIRECTORY    SYMBOLIC(O_DIRECTORY) | ||||
|  | @ -52,6 +59,7 @@ COSMOPOLITAN_C_END_ | |||
| #define O_EXCL         SYMBOLIC(O_EXCL) | ||||
| #define O_EXEC         SYMBOLIC(O_EXEC) | ||||
| #define O_EXLOCK       SYMBOLIC(O_EXLOCK) | ||||
| #define O_INDEXED      SYMBOLIC(O_INDEXED) | ||||
| #define O_LARGEFILE    SYMBOLIC(O_LARGEFILE) | ||||
| #define O_NDELAY       SYMBOLIC(O_NDELAY) | ||||
| #define O_NOATIME      SYMBOLIC(O_NOATIME) | ||||
|  | @ -61,8 +69,6 @@ COSMOPOLITAN_C_END_ | |||
| #define O_NONBLOCK     SYMBOLIC(O_NONBLOCK) | ||||
| #define O_PATH         SYMBOLIC(O_PATH) | ||||
| #define O_RANDOM       SYMBOLIC(O_RANDOM) | ||||
| #define O_RDONLY       SYMBOLIC(O_RDONLY) | ||||
| #define O_RDWR         SYMBOLIC(O_RDWR) | ||||
| #define O_RSYNC        SYMBOLIC(O_RSYNC) | ||||
| #define O_SEARCH       SYMBOLIC(O_SEARCH) | ||||
| #define O_SEQUENTIAL   SYMBOLIC(O_SEQUENTIAL) | ||||
|  | @ -73,6 +79,5 @@ COSMOPOLITAN_C_END_ | |||
| #define O_TRUNC        SYMBOLIC(O_TRUNC) | ||||
| #define O_TTY_INIT     SYMBOLIC(O_TTY_INIT) | ||||
| #define O_VERIFY       SYMBOLIC(O_VERIFY) | ||||
| #define O_WRONLY       SYMBOLIC(O_WRONLY) | ||||
| 
 | ||||
| #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_O_H_ */ | ||||
|  |  | |||
|  | @ -23,7 +23,6 @@ | |||
| #include "libc/sysv/consts/map.h" | ||||
| #include "libc/sysv/consts/nr.h" | ||||
| #include "libc/sysv/consts/prot.h" | ||||
| #include "libc/sysv/consts/prot.h" | ||||
| 
 | ||||
| /*                                           ▄▄▄ | ||||
|                        ▄▄▄                    ▀▓▓▒▄ | ||||
|  | @ -418,11 +417,13 @@ _init_systemfive_stack: | |||
| //	m.p[0].h	32	8 | ||||
| //	m.p[0].prot	40	4 | ||||
| //	m.p[0].flags	44	4 | ||||
| //	m.p[0].offset	48	8 | ||||
| //	m.p[0].size	56	8 | ||||
| 	.weak	_mmi
 | ||||
| 	ezlea	_mmi,cx | ||||
| 	test	%rcx,%rcx | ||||
| 	push	%r9					# save the stack size | ||||
| 	jz	3f | ||||
| 	push	%r9					# save the stack size | ||||
| 	lea	-1(%r11,%r9),%r9			# need incl. interval | ||||
| 	shr	$16,%r11				# for the stack range | ||||
| 	shr	$16,%r9 | ||||
|  | @ -432,8 +433,9 @@ _init_systemfive_stack: | |||
| 	orq	$-1,32(%rcx)				# _mmi.s[0].h | ||||
| 	mov	%edx,40(%rcx)				# _mmi.s[0].prot | ||||
| 	mov	%r10d,44(%rcx)				# _mmi.s[0].flags | ||||
| 3:	pop	%r9					# restore stack size | ||||
| 	pop	%rsi | ||||
| 	pop	%r9					# restore stack size | ||||
| 	mov	%r9,56(%rcx)				# _mmi.s[0].size | ||||
| 3:	pop	%rsi | ||||
| 	pop	%rdi | ||||
| 	leave | ||||
| //	switch stacks | ||||
|  |  | |||
|  | @ -76,11 +76,17 @@ TEST(mkntcmdline, fix) { | |||
|   char *argv1[] = { | ||||
|       "C:/WINDOWS/system32/cmd.exe", | ||||
|       "/C", | ||||
|       "more < \"C:\\Users\\jtunn\\AppData\\Local\\Temp\\tmplquaa_d6\"", | ||||
|       "more < \"C:\\Users\\jart\\AppData\\Local\\Temp\\tmplquaa_d6\"", | ||||
|       NULL, | ||||
|   }; | ||||
|   EXPECT_NE(-1, mkntcmdline(cmdline, argv1[0], argv1)); | ||||
|   EXPECT_STREQ(u"C:\\WINDOWS\\system32\\cmd.exe /C \"more < " | ||||
|                u"\\\"C:\\Users\\jtunn\\AppData\\Local\\Temp\\tmplquaa_d6\\\"\"", | ||||
|                u"\\\"C:\\Users\\jart\\AppData\\Local\\Temp\\tmplquaa_d6\\\"\"", | ||||
|                cmdline); | ||||
| } | ||||
| 
 | ||||
| TEST(mkntcmdline, testWut) { | ||||
|   char *argv[] = {"redbean.com", "--strace", NULL}; | ||||
|   EXPECT_NE(-1, mkntcmdline(cmdline, "C:\\Users\\jart\\redbean.com", argv)); | ||||
|   EXPECT_STREQ(u"C:\\Users\\jart\\redbean.com --strace", cmdline); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										40
									
								
								test/libc/intrin/describeflags_test.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								test/libc/intrin/describeflags_test.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| /*-*- 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 2022 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/intrin/describeflags.internal.h" | ||||
| #include "libc/intrin/kprintf.h" | ||||
| #include "libc/macros.internal.h" | ||||
| #include "libc/testlib/testlib.h" | ||||
| 
 | ||||
| static const struct DescribeFlags kFlags[] = { | ||||
|     {1, "hi"},     //
 | ||||
|     {2, "there"},  //
 | ||||
| }; | ||||
| 
 | ||||
| const char *DescribeIt(uint32_t x) { | ||||
|   static char s[64]; | ||||
|   return DescribeFlags(s, ARRAYLEN(s), kFlags, ARRAYLEN(kFlags), "x", x); | ||||
| } | ||||
| 
 | ||||
| TEST(describeflags, test) { | ||||
|   EXPECT_STREQ("0", DescribeIt(0)); | ||||
|   EXPECT_STREQ("xhi", DescribeIt(1)); | ||||
|   EXPECT_STREQ("xthere", DescribeIt(2)); | ||||
|   EXPECT_STREQ("xhi|xthere", DescribeIt(3)); | ||||
|   EXPECT_STREQ("xhi|xthere|0x14", DescribeIt(0x17)); | ||||
| } | ||||
|  | @ -155,6 +155,9 @@ static const struct { | |||
|     {"\"\\001\"", "%#s", S("\1")},                        //
 | ||||
|     {"", "%.*s", 0},                                      //
 | ||||
|     {"☺☻♥♦♣♠!", "%hhs", S("\1\2\3\4\5\6!")},              //
 | ||||
|     {"☺☻", "%.*hhs", 2, S("\1\2\3\4\5\6!")},              //
 | ||||
|     {"u\"☺☻\"", "%#.*hhs", 2, S("\1\2\3\4\5\6!")},        //
 | ||||
|     {"u\" ☻\"", "%#.*hhs", 2, S("\0\2\3\4\5\6!")},        //
 | ||||
|     {"", "% s", S("")},                                   //
 | ||||
|     {" a", "% s", S("a")},                                //
 | ||||
|     {"", "% .*s", 0, S("a")},                             //
 | ||||
|  |  | |||
|  | @ -65,7 +65,7 @@ static void RunTrackMemoryIntervalTest(const struct MemoryIntervals t[2], int x, | |||
|   struct MemoryIntervals *mm; | ||||
|   mm = memcpy(malloc(sizeof(*t)), t, sizeof(*t)); | ||||
|   CheckMemoryIntervalsAreOk(mm); | ||||
|   CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0)); | ||||
|   CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0)); | ||||
|   CheckMemoryIntervalsAreOk(mm); | ||||
|   CheckMemoryIntervalsEqual(mm, t + 1); | ||||
|   free(mm); | ||||
|  | @ -102,10 +102,10 @@ TEST(TrackMemoryInterval, TestFull) { | |||
|   mm = calloc(1, sizeof(struct MemoryIntervals)); | ||||
|   for (i = 0; i < mm->n; ++i) { | ||||
|     CheckMemoryIntervalsAreOk(mm); | ||||
|     CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0)); | ||||
|     CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0, 0, 0)); | ||||
|     CheckMemoryIntervalsAreOk(mm); | ||||
|   } | ||||
|   CHECK_EQ(-1, TrackMemoryInterval(mm, i, i, i, 0, 0)); | ||||
|   CHECK_EQ(-1, TrackMemoryInterval(mm, i, i, i, 0, 0, 0, 0)); | ||||
|   CHECK_EQ(ENOMEM, errno); | ||||
|   CheckMemoryIntervalsAreOk(mm); | ||||
|   free(mm); | ||||
|  |  | |||
|  | @ -3112,7 +3112,7 @@ int main(int argc, char *argv[]) { | |||
|   m->mode = XED_MACHINE_MODE_LONG_64; | ||||
|   m->onbinbase = OnBinbase; | ||||
|   m->onlongbranch = OnLongBranch; | ||||
|   speed = 32; | ||||
|   speed = 4; | ||||
|   SetXmmSize(2); | ||||
|   SetXmmDisp(kXmmHex); | ||||
|   if ((colorize = !__nocolor)) { | ||||
|  |  | |||
|  | @ -914,7 +914,6 @@ static void SetDefaults(void) { | |||
|   ProgramTimeout(60 * 1000); | ||||
|   ProgramSslTicketLifetime(24 * 60 * 60); | ||||
|   sslfetchverify = true; | ||||
|   if (IsWindows()) uniprocess = true; | ||||
| } | ||||
| 
 | ||||
| static void AddString(struct Strings *l, const char *s, size_t n) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue