Improve system call support

This commit is contained in:
Justine Tunney 2021-08-25 21:35:58 -07:00
parent 63b867bd2f
commit 3085ac7837
65 changed files with 900 additions and 544 deletions

View file

@ -87,6 +87,7 @@ int chdir(const char *);
int chmod(const char *, uint32_t);
int chown(const char *, uint32_t, uint32_t);
int chroot(const char *);
int clone(int (*)(void *), void *, int, void *, ...);
int close(int);
int closedir(DIR *);
int creat(const char *, uint32_t);

View file

@ -28,7 +28,7 @@
* @asyncsignalsafe
* @vforksafe
*/
nodiscard int dup(int fd) {
int dup(int fd) {
if (!IsWindows()) {
return sys_dup(fd);
} else {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/ntspawn.h"
#include "libc/mem/alloca.h"
@ -44,6 +45,8 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
startinfo.hStdError = g_fds.p[2].handle;
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
if (rc == -1) return -1;
CloseHandle(g_fds.p[0].handle);
CloseHandle(g_fds.p[1].handle);
CloseHandle(procinfo.hThread);
do {
WaitForSingleObject(procinfo.hProcess, -1);

View file

@ -30,7 +30,8 @@
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_fadvise_nt(int fd, uint64_t offset, uint64_t len, int advice) {
textwindows int sys_fadvise_nt(int fd, uint64_t offset, uint64_t len,
int advice) {
int64_t h2;
NtStatus status;
uint32_t sharemode;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
@ -26,26 +27,44 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Returns true if file exists at path.
*
* This function is equivalent to:
*
* struct stat st;
* return stat(path, &st) != -1;
*
* Please note that things which aren't strictly files, e.g. directories
* or sockets, could be considered files for the purposes of this
* function. The stat() function may be used to differentiate them.
*/
bool fileexists(const char *path) {
int rc, olderr;
int e;
struct stat st;
struct ZiposUri zipname;
uint16_t path16[PATH_MAX];
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
olderr = errno;
rc = __sys_fstatat(AT_FDCWD, path, &st, 0);
if (rc == -1 && (errno == ENOENT || errno == ENOTDIR)) {
errno = olderr;
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
e = errno;
if (weaken(__zipos_stat)(&zipname, &st) != -1) {
return true;
} else {
errno = e;
return false;
}
} else if (IsMetal()) {
return false;
} else if (!IsWindows()) {
e = errno;
if (__sys_fstatat(AT_FDCWD, path, &st, 0) != -1) {
return true;
} else {
errno = e;
return false;
}
return rc != -1;
} else {
if (__mkntpath(path, path16) == -1) return -1;
return GetFileAttributes(path16) != -1u;

View file

@ -16,11 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/fileinfobyhandleclass.h"
@ -37,12 +38,6 @@
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h"
#if 0
#define DEBUG(FMT, ...) (dprintf)(2, FMT "\n", ##__VA_ARGS__)
#else
#define DEBUG(FMT, ...) (void)0
#endif
static textwindows uint32_t GetSizeOfReparsePoint(int64_t fh) {
wint_t x, y;
const char16_t *p;
@ -69,7 +64,7 @@ static textwindows uint32_t GetSizeOfReparsePoint(int64_t fh) {
z += x < 0200 ? 1 : bsrl(tpenc(x)) >> 3;
}
} else {
DEBUG("GetSizeOfReparsePoint failed %d", GetLastError());
SYSDEBUG("GetSizeOfReparsePoint failed %d", GetLastError());
}
return z;
}
@ -122,8 +117,10 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
&fci, sizeof(fci))) {
actualsize = fci.CompressedFileSize;
}
st->st_blocks = roundup(actualsize, PAGESIZE) / 512;
st->st_blocks = ROUNDUP(actualsize, PAGESIZE) / 512;
}
} else {
SYSDEBUG("GetFileInformationByHandle failed %d", GetLastError());
}
break;
default:
@ -131,6 +128,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
}
return 0;
} else {
SYSDEBUG("GetFileType failed %d", GetLastError());
return __winerr();
}
}

View file

@ -109,9 +109,9 @@ char *sys_getcwd(char *, u64) hidden;
char *sys_getcwd_xnu(char *, u64) hidden;
i32 __sys_dup3(i32, i32, i32) hidden;
i32 __sys_execve(const char *, char *const[], char *const[]) hidden;
i32 __sys_fcntl(i32, i32, u64) hidden;
i32 __sys_fstat(i32, struct stat *) hidden;
i32 __sys_fstatat(i32, const char *, struct stat *, i32) hidden;
i32 __sys_fcntl(i32, i32, ...) hidden;
i32 __sys_fstat(i32, void *) hidden;
i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
i32 __sys_getrusage(i32, struct rusage *) hidden;
i32 __sys_openat(i32, const char *, i32, u32) hidden;
i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;

View file

@ -16,21 +16,56 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/metastat.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Returns true if file descriptor is backed by character i/o.
*
* This function is equivalent to:
*
* struct stat st;
* return stat(path, &st) != -1 && S_ISCHR(st.st_mode);
*
* Except faster and with fewer dependencies.
*
* @see isregularfile(), isdirectory(), issymlink(), fileexists()
*/
textstartup bool32 ischardev(int fd) {
int olderr;
struct stat st;
olderr = errno;
if (fstat(fd, &st) != -1) {
return S_ISCHR(st.st_mode);
bool32 ischardev(int fd) {
int e;
union metastat st;
if (__isfdkind(fd, kFdZip)) {
e = errno;
if (weaken(__zipos_fstat)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, &st.linux) !=
-1) {
return S_ISCHR(st.linux.st_mode);
} else {
errno = e;
return false;
}
} else if (IsMetal()) {
return true;
} else if (!IsWindows()) {
e = errno;
if (__sys_fstat(fd, &st) != -1) {
return S_ISCHR(METASTAT(st, st_mode));
} else {
errno = e;
return false;
}
} else {
errno = olderr;
return false;
return __isfdkind(fd, kFdConsole) ||
(__isfdkind(fd, kFdFile) &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
}
}

View file

@ -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/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/metastat.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
@ -25,19 +27,44 @@
#include "libc/nt/files.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Returns true if file exists and is a directory.
*
* This function is equivalent to:
*
* struct stat st;
* return fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1 &&
* S_ISDIR(st.st_mode);
*
* Except faster and with fewer dependencies.
*
* @see isregularfile(), issymlink(), ischardev()
*/
bool isdirectory(const char *path) {
struct stat st;
int rc, olderr;
int rc, e;
union metastat st;
struct ZiposUri zipname;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
olderr = errno;
rc = sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW);
if (rc == -1 && (errno == ENOENT || errno == ENOTDIR)) errno = olderr;
return rc != -1 && S_ISDIR(st.st_mode);
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
e = errno;
if (weaken(__zipos_stat)(&zipname, &st.linux) != -1) {
return S_ISDIR(st.linux.st_mode);
} else {
errno = e;
return false;
}
} else if (IsMetal()) {
return false;
} else if (!IsWindows()) {
e = errno;
if (__sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1) {
return S_ISDIR(METASTAT(st, st_mode));
} else {
errno = e;
return false;
}
} else {
return isdirectory_nt(path);
}

View file

@ -16,29 +16,52 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/metastat.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Returns true if file exists and is a regular file.
*
* This function is equivalent to:
*
* return fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1 &&
* S_ISREG(st.st_mode);
*
* Except faster and with fewer dependencies.
*
* @see isdirectory(), ischardev(), issymlink()
*/
bool isregularfile(const char *path) {
struct stat st;
int rc, olderr;
int rc, e;
union metastat st;
struct ZiposUri zipname;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
olderr = errno;
rc = sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW);
if (rc == -1 && (errno == ENOENT || errno == ENOTDIR)) {
errno = olderr;
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
e = errno;
if (weaken(__zipos_stat)(&zipname, &st.linux) != -1) {
return S_ISREG(st.linux.st_mode);
} else {
errno = e;
return false;
}
} else if (IsMetal()) {
return false;
} else if (!IsWindows()) {
e = errno;
if (__sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1) {
return S_ISREG(METASTAT(st, st_mode));
} else {
errno = e;
return false;
}
return rc != -1 && S_ISREG(st.st_mode);
} else {
return isregularfile_nt(path);
}

View file

@ -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/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/metastat.internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
@ -25,19 +27,38 @@
#include "libc/nt/files.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
/**
* Returns true if file exists and is a symbolic link.
*
* This function is equivalent to:
*
* struct stat st;
* return fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1 &&
* S_ISLNK(st.st_mode);
*
* Except faster and with fewer dependencies.
*
* @see isregularfile(), isdirectory(), fileexists(), ischardev()
*/
bool issymlink(const char *path) {
struct stat st;
int rc, olderr;
int e;
union metastat st;
struct ZiposUri zipname;
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
if (!IsWindows()) {
olderr = errno;
rc = sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW);
if (rc == -1 && (errno == ENOENT || errno == ENOTDIR)) errno = olderr;
return rc != -1 && S_ISLNK(st.st_mode);
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
return false;
} else if (IsMetal()) {
return false;
} else if (!IsWindows()) {
e = errno;
if (__sys_fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1) {
return S_ISLNK(METASTAT(st, st_mode));
} else {
errno = e;
return false;
}
} else {
return issymlink_nt(path);
}

View file

@ -19,6 +19,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/securityimpersonationlevel.h"
@ -34,12 +35,6 @@
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
#if 0
#define DEBUG(FMT, ...) (dprintf)(2, FMT "\n", ##__VA_ARGS__)
#else
#define DEBUG(FMT, ...) (void)0
#endif
/**
* Asks Microsoft if we're authorized to use a folder or file.
*
@ -92,24 +87,24 @@ TryAgain:
if (result || flags == F_OK) {
rc = 0;
} else {
DEBUG("ntaccesscheck finale failed %d %d", result, flags);
SYSDEBUG("ntaccesscheck finale failed %d %d", result, flags);
rc = eacces();
}
} else {
rc = __winerr();
DEBUG("AccessCheck failed: %m");
SYSDEBUG("AccessCheck failed: %m");
}
} else {
rc = __winerr();
DEBUG("DuplicateToken failed: %m");
SYSDEBUG("DuplicateToken failed: %m");
}
} else {
rc = __winerr();
DEBUG("OpenProcessToken failed: %m");
SYSDEBUG("OpenProcessToken failed: %m");
}
} else {
e = GetLastError();
DEBUG("GetFileSecurity failed: %d %d", e, secsize);
SYSDEBUG("GetFileSecurity failed: %d %d", e, secsize);
if (!IsTiny() && e == kNtErrorInsufficientBuffer) {
if (!freeme && weaken(malloc) && (freeme = weaken(malloc)(secsize))) {
s = freeme;

View file

@ -17,28 +17,45 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
int fd, err;
err = errno;
fd = __sys_openat(dirfd, file, flags, mode);
static bool once, modernize;
int d, e, f;
/*
* RHEL5 doesn't support O_CLOEXEC
* What on earth is it doing here?
* It returns -530!
* RHEL5 doesn't support O_CLOEXEC. It's hard to test for this.
* Sometimes the system call succeeds and it just doesn't set the
* flag. Other times, it return -530 which makes no sense.
*/
if (IsLinux() && fd == -1 && errno > 255) {
errno = err;
fd = __sys_openat(dirfd, file, flags & ~O_CLOEXEC, mode);
if (fd != -1 && (flags & O_CLOEXEC)) {
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
if (!IsLinux() || !(flags & O_CLOEXEC) || modernize) {
return __sys_openat(dirfd, file, flags, mode);
} else if (once) {
if ((d = __sys_openat(dirfd, file, flags & ~O_CLOEXEC, mode)) != -1) {
e = errno;
if (__sys_fcntl(d, F_SETFD, FD_CLOEXEC) == -1) {
errno = e;
}
}
} else {
e = errno;
if ((d = __sys_openat(dirfd, file, flags, mode)) != -1) {
if ((f = __sys_fcntl(d, F_GETFD)) != -1) {
if (f & FD_CLOEXEC) {
modernize = true;
} else {
__sys_fcntl(d, F_SETFD, FD_CLOEXEC);
}
}
errno = e;
once = true;
} else if (errno > 255) {
once = true;
return sys_openat(dirfd, file, flags, mode);
}
}
return fd;
return d;
}

View file

@ -45,10 +45,6 @@ int openat(int dirfd, const char *file, int flags, ...) {
va_list va;
unsigned mode;
struct ZiposUri zipname;
if (strstr(file, "0/o/dbg/test")) {
(dprintf)(2, "-- wut %`'s\n", file);
if (weaken(__die)) weaken(__die)();
}
va_start(va, flags);
mode = va_arg(va, unsigned);
va_end(va);

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/framebuffervirtualscreeninfo.h"
#include "libc/dce.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/system.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
@ -70,9 +71,9 @@ int reboot(int howto) {
if (howto == 0xD000FCE2u) {
ok = !!SetSuspendState(0, 0, 0);
} else {
howto |= kNtShutdownForceOthers;
howto |= kNtShutdownForceSelf;
if (NtGetVersion() >= 8) {
howto |= kNtShutdownForceOthers;
if (NtGetVersion() >= kNtVersionWindows8) {
howto |= kNtShutdownHybrid;
}
if (immediately) {

View file

@ -5,6 +5,14 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define METASTAT(x, field) \
(IsLinux() || IsMetal() ? x.linux.field \
: IsXnu() ? x.xnu.field \
: IsFreebsd() ? x.freebsd.field \
: IsOpenbsd() ? x.openbsd.field \
: IsNetbsd() ? x.netbsd.field \
: 0)
struct stat_xnu {
int32_t st_dev;
uint16_t st_mode, st_nlink;

View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SYSDEBUG_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_SYSDEBUG_INTERNAL_H_
#include "libc/calls/calls.h"
#if 0
#define SYSDEBUG(FMT, ...) (dprintf)(2, FMT "\n", ##__VA_ARGS__)
#else
#define SYSDEBUG(FMT, ...) (void)0
#endif
#endif /* COSMOPOLITAN_LIBC_CALLS_SYSDEBUG_INTERNAL_H_ */

View file

@ -16,9 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/rusage.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/nt/accounting.h"
@ -62,12 +64,21 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
dwExitCode = kNtStillActive;
if (options & WNOHANG) {
i = WaitForMultipleObjects(count, handles, false, 0);
if (i == kNtWaitTimeout) return 0;
if (i == kNtWaitTimeout) {
return 0;
}
} else {
i = WaitForMultipleObjects(count, handles, false, -1);
}
if (i == kNtWaitFailed) return __winerr();
if (!GetExitCodeProcess(handles[i], &dwExitCode)) return __winerr();
if (i == kNtWaitFailed) {
SYSDEBUG("WaitForMultipleObjects failed %d", GetLastError());
return __winerr();
}
assert(__isfdkind(pids[i], kFdProcess));
if (!GetExitCodeProcess(handles[i], &dwExitCode)) {
SYSDEBUG("GetExitCodeProcess failed %d", GetLastError());
return __winerr();
}
if (dwExitCode == kNtStillActive) continue;
if (opt_out_wstatus) { /* @see WEXITSTATUS() */
*opt_out_wstatus = (dwExitCode & 0xff) << 8;
@ -76,14 +87,12 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
memset(opt_out_rusage, 0, sizeof(*opt_out_rusage));
if (GetProcessTimes(g_fds.p[pids[i]].handle, &createfiletime,
&exitfiletime, &kernelfiletime, &userfiletime)) {
opt_out_rusage->ru_utime.tv_sec =
ReadFileTime(userfiletime) / HECTONANOSECONDS;
opt_out_rusage->ru_utime.tv_usec =
ReadFileTime(userfiletime) % HECTONANOSECONDS;
opt_out_rusage->ru_stime.tv_sec =
ReadFileTime(kernelfiletime) / HECTONANOSECONDS;
opt_out_rusage->ru_stime.tv_usec =
ReadFileTime(kernelfiletime) % HECTONANOSECONDS;
opt_out_rusage->ru_utime =
WindowsDurationToTimeVal(ReadFileTime(userfiletime));
opt_out_rusage->ru_stime =
WindowsDurationToTimeVal(ReadFileTime(kernelfiletime));
} else {
SYSDEBUG("GetProcessTimes failed %d", GetLastError());
}
}
CloseHandle(g_fds.p[pids[i]].handle);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/calls/ucontext.h"
#include "libc/nt/enum/exceptionhandleractions.h"
#include "libc/nt/enum/signal.h"
@ -29,6 +30,7 @@ textwindows unsigned __wincrash(struct NtExceptionPointers *ep) {
ucontext_t ctx;
struct siginfo si;
} g;
SYSDEBUG("__wincrash");
switch (ep->ExceptionRecord->ExceptionCode) {
case kNtSignalBreakpoint:
sig = SIGTRAP;