Numerous msvcrt/crt fixes; support variable resolution

This commit is contained in:
2025-11-03 21:46:29 -07:00
parent b62b01ffca
commit 73b1ffb8d6
6 changed files with 272 additions and 160 deletions

View File

@@ -15,6 +15,25 @@
#include <unistd.h> #include <unistd.h>
#include <vector> #include <vector>
namespace {
FILE *mapToHostFile(_FILE *file) {
if (!file)
return nullptr;
switch (file->_file) {
case STDIN_FILENO:
return stdin;
case STDOUT_FILENO:
return stdout;
case STDERR_FILENO:
return stderr;
default:
return nullptr;
}
}
} // namespace
namespace crt { namespace crt {
int _commode = 0; int _commode = 0;
@@ -302,11 +321,14 @@ void *CDECL __acrt_iob_func(unsigned int index) {
return nullptr; return nullptr;
} }
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, FILE *stream, const char *format, void *locale, int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale,
va_list args) { va_list args) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args); DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args);
return vfprintf(stream, format, args); FILE *hostFile = mapToHostFile(stream);
if (!hostFile)
return -1;
return vfprintf(hostFile, format, args);
} }
int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format, int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,

View File

@@ -20,10 +20,12 @@ typedef enum _crt_argv_mode {
typedef void(_CC_CDECL *signal_handler)(int); typedef void(_CC_CDECL *signal_handler)(int);
typedef int(_CC_CDECL *sort_compare)(const void *, const void *); typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
using FILE = struct _IO_FILE;
namespace crt { namespace crt {
extern int _commode;
extern int _fmode;
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end); void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end); int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end);
void CDECL _set_app_type(_crt_app_type type); void CDECL _set_app_type(_crt_app_type type);
@@ -65,7 +67,7 @@ void CDECL _exit(int status);
void CDECL abort(); void CDECL abort();
signal_handler CDECL signal(int signum, signal_handler handler); signal_handler CDECL signal(int signum, signal_handler handler);
void *CDECL __acrt_iob_func(unsigned int index); void *CDECL __acrt_iob_func(unsigned int index);
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, FILE *stream, const char *format, void *locale, int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale,
va_list args); va_list args);
int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format, int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,
void *locale, va_list args); void *locale, va_list args);

View File

@@ -34,6 +34,7 @@
#include <mutex> #include <mutex>
#include <optional> #include <optional>
#include <spawn.h> #include <spawn.h>
#include <stdio.h>
#include <string> #include <string>
#include <strings.h> #include <strings.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -50,7 +51,48 @@
#define O_BINARY 0 #define O_BINARY 0
#endif #endif
using _onexit_t = _PIFV; namespace {
std::mutex g_fileMutex;
std::unordered_map<int, FILE *> g_files;
FILE *mapToHostFile(_FILE *file) {
if (!file)
return nullptr;
switch (file->_file) {
case -1:
return nullptr;
case STDIN_FILENO:
return stdin;
case STDOUT_FILENO:
return stdout;
case STDERR_FILENO:
return stderr;
default:
return g_files[file->_file];
}
}
_FILE *mapToGuestFile(FILE *file) {
if (!file)
return nullptr;
int fd = file->_fileno;
_FILE *out = new (wibo::heap::guestMalloc(sizeof(_FILE))) _FILE(fd);
std::lock_guard lock(g_fileMutex);
g_files[fd] = file;
return out;
}
int closeGuestFile(_FILE *file) {
if (!file)
return -1;
int fd = file->_file;
std::lock_guard lock(g_fileMutex);
g_files.erase(fd);
return close(fd);
}
} // namespace
namespace msvcrt { namespace msvcrt {
int _commode; int _commode;
@@ -59,13 +101,15 @@ namespace msvcrt {
uint16_t** __winitenv; uint16_t** __winitenv;
uint16_t* _wpgmptr = nullptr; uint16_t* _wpgmptr = nullptr;
char* _pgmptr = nullptr; char* _pgmptr = nullptr;
int __mb_cur_max = 1;
_FILE _iob[_IOB_ENTRIES] = {_FILE{STDOUT_FILENO}, _FILE{STDERR_FILENO}, _FILE{STDIN_FILENO}};
constexpr int MB_CP_ANSI = -3; constexpr int MB_CP_ANSI = -3;
constexpr int MB_CP_OEM = -2; constexpr int MB_CP_OEM = -2;
constexpr int MB_CP_LOCALE = -4; constexpr int MB_CP_LOCALE = -4;
constexpr int MB_CP_SBCS = 0; constexpr int MB_CP_SBCS = 0;
constexpr int MB_CP_UTF8 = -5; constexpr int MB_CP_UTF8 = -5;
static unsigned int mbCurMaxValue = 1;
static int mbCodePageSetting = MB_CP_ANSI; static int mbCodePageSetting = MB_CP_ANSI;
static unsigned int floatingPointControlWord = 0x0009001F; // _CW_DEFAULT for x87 static unsigned int floatingPointControlWord = 0x0009001F; // _CW_DEFAULT for x87
@@ -103,7 +147,7 @@ namespace msvcrt {
} }
} }
unsigned int mbCurMaxForCodePage(int codepage); int mbCurMaxForCodePage(int codepage);
void updateMbctypeForCodePage(int codepage) { void updateMbctypeForCodePage(int codepage) {
auto &table = mbctypeTable(); auto &table = mbctypeTable();
@@ -158,7 +202,7 @@ namespace msvcrt {
void ensureMbctypeInitialized() { void ensureMbctypeInitialized() {
std::call_once(mbctypeInitFlag(), []() { std::call_once(mbctypeInitFlag(), []() {
updateMbctypeForCodePage(mbCodePageSetting); updateMbctypeForCodePage(mbCodePageSetting);
mbCurMaxValue = mbCurMaxForCodePage(mbCodePageSetting); __mb_cur_max = mbCurMaxForCodePage(mbCodePageSetting);
}); });
} }
@@ -205,52 +249,21 @@ namespace msvcrt {
return storage; return storage;
} }
IOBProxy *standardIobEntries() { _FILE *standardIobEntries() {
static IOBProxy entries[3] = {}; return _iob;
return entries;
} }
IOBProxy *CDECL __iob_func() { _FILE *CDECL __iob_func() {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
return standardIobEntries(); return _iob;
} }
IOBProxy *CDECL __p__iob() { _FILE *CDECL __p__iob() {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
return standardIobEntries(); return _iob;
} }
std::unordered_map<void *, FILE *> &iobMapping() { void CDECL setbuf(_FILE *stream, char *buffer) {
static std::unordered_map<void *, FILE *> mapping;
return mapping;
}
std::once_flag &iobInitFlag() {
static std::once_flag flag;
return flag;
}
void initializeIobMapping() {
std::call_once(iobInitFlag(), []() {
auto &mapping = iobMapping();
IOBProxy *entries = standardIobEntries();
mapping.emplace(static_cast<void *>(&entries[0]), stdin);
mapping.emplace(static_cast<void *>(&entries[1]), stdout);
mapping.emplace(static_cast<void *>(&entries[2]), stderr);
});
}
FILE *mapToHostFile(FILE *stream) {
initializeIobMapping();
auto &mapping = iobMapping();
auto it = mapping.find(stream);
if (it != mapping.end()) {
return it->second;
}
return stream;
}
void CDECL setbuf(FILE *stream, char *buffer) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("setbuf(%p, %p)\n", stream, buffer); DEBUG_LOG("setbuf(%p, %p)\n", stream, buffer);
if (!stream) { if (!stream) {
@@ -329,7 +342,7 @@ namespace msvcrt {
ext ? ext : ""); ext ? ext : "");
} }
int CDECL _fileno(FILE *stream) { int CDECL _fileno(_FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("_fileno(%p)\n", stream); DEBUG_LOG("_fileno(%p)\n", stream);
if (!stream) { if (!stream) {
@@ -340,7 +353,7 @@ namespace msvcrt {
return ::fileno(host); return ::fileno(host);
} }
unsigned int mbCurMaxForCodePage(int codepage) { int mbCurMaxForCodePage(int codepage) {
switch (codepage) { switch (codepage) {
case MB_CP_SBCS: case MB_CP_SBCS:
case MB_CP_ANSI: case MB_CP_ANSI:
@@ -363,7 +376,7 @@ namespace msvcrt {
void refreshMbCurMax() { void refreshMbCurMax() {
ensureMbctypeInitialized(); ensureMbctypeInitialized();
mbCurMaxValue = mbCurMaxForCodePage(mbCodePageSetting); __mb_cur_max = mbCurMaxForCodePage(mbCodePageSetting);
} }
int CDECL _getmbcp() { int CDECL _getmbcp() {
@@ -373,11 +386,11 @@ namespace msvcrt {
return mbCodePageSetting; return mbCodePageSetting;
} }
unsigned int* CDECL __p___mb_cur_max() { int* CDECL __p___mb_cur_max() {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
ensureMbctypeInitialized(); ensureMbctypeInitialized();
DEBUG_LOG("__p___mb_cur_max() -> %u\n", mbCurMaxValue); DEBUG_LOG("__p___mb_cur_max() -> %u\n", __mb_cur_max);
return &mbCurMaxValue; return &__mb_cur_max;
} }
int CDECL _setmbcp(int codepage) { int CDECL _setmbcp(int codepage) {
@@ -402,7 +415,7 @@ namespace msvcrt {
mbCodePageSetting = codepage; mbCodePageSetting = codepage;
updateMbctypeForCodePage(codepage); updateMbctypeForCodePage(codepage);
mbCurMaxValue = mbCurMaxForCodePage(codepage); __mb_cur_max = mbCurMaxForCodePage(codepage);
return 0; return 0;
} }
@@ -729,11 +742,20 @@ namespace msvcrt {
return 0; return 0;
} }
_PIFV CDECL _onexit(_PIFV func) { static void runExitFunc(int status, void *arg) {
(void)status;
(void)call__onexit_t(reinterpret_cast<_onexit_t>(arg));
}
_onexit_t CDECL _onexit(_onexit_t func) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("_onexit(%p)\n", func); DEBUG_LOG("_onexit(%p)\n", func);
if(!func) return nullptr; if (!func) {
if (atexit(reinterpret_cast<void (*)()>(func)) != 0) return nullptr; return nullptr;
}
if (on_exit(runExitFunc, reinterpret_cast<void *>(func)) != 0) {
return nullptr;
}
return func; return func;
} }
@@ -1129,7 +1151,7 @@ namespace msvcrt {
return result; return result;
} }
char *CDECL fgets(char *str, int count, FILE *stream) { char *CDECL fgets(char *str, int count, _FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fgets(%p, %d, %p)\n", str, count, stream); DEBUG_LOG("fgets(%p, %d, %p)\n", str, count, stream);
if (!str || count <= 0) { if (!str || count <= 0) {
@@ -1139,14 +1161,14 @@ namespace msvcrt {
return ::fgets(str, count, host); return ::fgets(str, count, host);
} }
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, FILE *stream) { SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, _FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fread(%p, %zu, %zu, %p)\n", buffer, size, count, stream); DEBUG_LOG("fread(%p, %zu, %zu, %p)\n", buffer, size, count, stream);
FILE *host = mapToHostFile(stream); FILE *host = mapToHostFile(stream);
return ::fread(buffer, size, count, host); return ::fread(buffer, size, count, host);
} }
FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag) { _FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("_fsopen(%s, %s, %d)\n", filename ? filename : "(null)", mode ? mode : "(null)", shflag); DEBUG_LOG("_fsopen(%s, %s, %d)\n", filename ? filename : "(null)", mode ? mode : "(null)", shflag);
(void)shflag; (void)shflag;
@@ -1155,7 +1177,7 @@ namespace msvcrt {
return nullptr; return nullptr;
} }
auto hostPath = files::pathFromWindows(filename); auto hostPath = files::pathFromWindows(filename);
return ::fopen(hostPath.c_str(), mode); return mapToGuestFile(::fopen(hostPath.c_str(), mode));
} }
int CDECL _sopen(const char *path, int oflag, int shflag, int pmode) { int CDECL _sopen(const char *path, int oflag, int shflag, int pmode) {
@@ -1802,13 +1824,18 @@ namespace msvcrt {
return std::memcmp(lhs, rhs, count); return std::memcmp(lhs, rhs, count);
} }
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, int (*compar)(const void *, const void *)) { static thread_local sort_compare currentCompare = nullptr;
static int doCompare(const void *a, const void *b) { return call_sort_compare(currentCompare, a, b); }
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compar); DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compare);
std::qsort(base, num, size, compar); currentCompare = compare;
::qsort(base, num, size, doCompare);
} }
int CDECL fflush(FILE *stream) { int CDECL fflush(_FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fflush(%p)\n", stream); DEBUG_LOG("fflush(%p)\n", stream);
if (!stream) { if (!stream) {
@@ -1818,10 +1845,10 @@ namespace msvcrt {
return std::fflush(host); return std::fflush(host);
} }
int CDECL_NO_CONV vfwprintf(FILE *stream, const uint16_t *format, va_list args) { int CDECL_NO_CONV vfwprintf(_FILE *stream, const uint16_t *format, va_list args) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("vfwprintf(%p, %s, ...)\n", stream, wideStringToString(format).c_str()); DEBUG_LOG("vfwprintf(%p, %s, ...)\n", stream, wideStringToString(format).c_str());
FILE *host = mapToHostFile(stream ? stream : stdout); FILE *host = mapToHostFile(stream ? stream : &_iob[0]);
std::wstring fmt; std::wstring fmt;
if (format) { if (format) {
for (const uint16_t *ptr = format; *ptr; ++ptr) { for (const uint16_t *ptr = format; *ptr; ++ptr) {
@@ -1832,10 +1859,10 @@ namespace msvcrt {
return std::vfwprintf(host, fmt.c_str(), args); return std::vfwprintf(host, fmt.c_str(), args);
} }
FILE *CDECL fopen(const char *filename, const char *mode) { _FILE *CDECL fopen(const char *filename, const char *mode) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fopen(%s, %s)\n", filename ? filename : "(null)", mode ? mode : "(null)"); DEBUG_LOG("fopen(%s, %s)\n", filename ? filename : "(null)", mode ? mode : "(null)");
return std::fopen(filename, mode); return mapToGuestFile(std::fopen(filename, mode));
} }
int CDECL _dup2(int fd1, int fd2) { int CDECL _dup2(int fd1, int fd2) {
@@ -1850,25 +1877,28 @@ namespace msvcrt {
return isatty(fd); return isatty(fd);
} }
int CDECL fseek(FILE *stream, long offset, int origin) { int CDECL fseek(_FILE *stream, long offset, int origin) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
VERBOSE_LOG("fseek(%p, %ld, %d)\n", stream, offset, origin); VERBOSE_LOG("fseek(%p, %ld, %d)\n", stream, offset, origin);
return std::fseek(stream, offset, origin); FILE* host = mapToHostFile(stream);
return std::fseek(host, offset, origin);
} }
long CDECL ftell(FILE *stream) { long CDECL ftell(_FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
VERBOSE_LOG("ftell(%p)\n", stream); VERBOSE_LOG("ftell(%p)\n", stream);
return std::ftell(stream); FILE* host = mapToHostFile(stream);
return std::ftell(host);
} }
int CDECL feof(FILE *stream) { int CDECL feof(_FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
VERBOSE_LOG("feof(%p)\n", stream); VERBOSE_LOG("feof(%p)\n", stream);
return std::feof(stream); FILE* host = mapToHostFile(stream);
return std::feof(host);
} }
int CDECL fputws(const uint16_t *str, FILE *stream) { int CDECL fputws(const uint16_t *str, _FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fputws(%s, %p)\n", wideStringToString(str).c_str(), stream); DEBUG_LOG("fputws(%s, %p)\n", wideStringToString(str).c_str(), stream);
std::wstring temp; std::wstring temp;
@@ -1877,23 +1907,25 @@ namespace msvcrt {
temp.push_back(static_cast<wchar_t>(*cursor)); temp.push_back(static_cast<wchar_t>(*cursor));
} }
} }
return std::fputws(temp.c_str(), stream); FILE* host = mapToHostFile(stream);
return std::fputws(temp.c_str(), host);
} }
int CDECL _cputws(const uint16_t *string) { int CDECL _cputws(const uint16_t *string) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("_cputws(%s)\n", wideStringToString(string).c_str()); DEBUG_LOG("_cputws(%s)\n", wideStringToString(string).c_str());
return fputws(string, stdout); return fputws(string, &_iob[0]);
} }
uint16_t* CDECL fgetws(uint16_t *buffer, int size, FILE *stream) { uint16_t* CDECL fgetws(uint16_t *buffer, int size, _FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fgetws(%p, %d, %p)\n", buffer, size, stream); DEBUG_LOG("fgetws(%p, %d, %p)\n", buffer, size, stream);
if (!buffer || size <= 0) { if (!buffer || size <= 0) {
return nullptr; return nullptr;
} }
std::vector<wchar_t> temp(static_cast<SIZE_T>(size)); std::vector<wchar_t> temp(static_cast<SIZE_T>(size));
wchar_t *res = std::fgetws(temp.data(), size, stream); FILE* host = mapToHostFile(stream);
wchar_t *res = std::fgetws(temp.data(), size, host);
if (!res) { if (!res) {
return nullptr; return nullptr;
} }
@@ -1906,13 +1938,14 @@ namespace msvcrt {
return buffer; return buffer;
} }
WINT_T CDECL fgetwc(FILE *stream) { WINT_T CDECL fgetwc(_FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
VERBOSE_LOG("fgetwc(%p)\n", stream); VERBOSE_LOG("fgetwc(%p)\n", stream);
return std::fgetwc(stream); FILE* host = mapToHostFile(stream);
return std::fgetwc(host);
} }
int CDECL _wfopen_s(FILE **stream, const uint16_t *filename, const uint16_t *mode) { int CDECL _wfopen_s(_FILE **stream, const uint16_t *filename, const uint16_t *mode) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("_wfopen_s(%p, %s, %s)\n", stream, wideStringToString(filename).c_str(), DEBUG_LOG("_wfopen_s(%p, %s, %s)\n", stream, wideStringToString(filename).c_str(),
wideStringToString(mode).c_str()); wideStringToString(mode).c_str());
@@ -1927,7 +1960,7 @@ namespace msvcrt {
*stream = nullptr; *stream = nullptr;
return errno ? errno : EINVAL; return errno ? errno : EINVAL;
} }
*stream = handle; *stream = mapToGuestFile(handle);
return 0; return 0;
} }
@@ -2210,21 +2243,14 @@ namespace msvcrt {
std::fflush(nullptr); std::fflush(nullptr);
} }
static FILE *resolveFileStream(FILE *stream) { int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args) {
if (!stream) {
return nullptr;
}
return mapToHostFile(stream);
}
int CDECL_NO_CONV vfprintf(FILE *stream, const char *format, va_list args) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("vfprintf(stream=%p, format=%s, args=%p)\n", stream, format, args); DEBUG_LOG("vfprintf(stream=%p, format=%s, args=%p)\n", stream, format, args);
if (!format || !stream) { if (!format || !stream) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
FILE *native = resolveFileStream(stream); FILE *native = mapToHostFile(stream);
if (!native) { if (!native) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@@ -2236,7 +2262,7 @@ namespace msvcrt {
return result; return result;
} }
int CDECL_NO_CONV fprintf(FILE *stream, const char *format, ...) { int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fprintf(%p, %s, ...)\n", stream, format); DEBUG_LOG("fprintf(%p, %s, ...)\n", stream, format);
va_list args; va_list args;
@@ -2246,14 +2272,14 @@ namespace msvcrt {
return result; return result;
} }
int CDECL fputc(int ch, FILE *stream) { int CDECL fputc(int ch, _FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fputc(%d, %p)\n", ch, stream); DEBUG_LOG("fputc(%d, %p)\n", ch, stream);
if (!stream) { if (!stream) {
errno = EINVAL; errno = EINVAL;
return EOF; return EOF;
} }
FILE *native = resolveFileStream(stream); FILE *native = mapToHostFile(stream);
if (!native) { if (!native) {
errno = EINVAL; errno = EINVAL;
return EOF; return EOF;
@@ -2261,14 +2287,14 @@ namespace msvcrt {
return std::fputc(ch, native); return std::fputc(ch, native);
} }
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, FILE *stream) { SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream) {
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
DEBUG_LOG("fwrite(%p, %zu, %zu, %p)\n", buffer, size, count, stream); DEBUG_LOG("fwrite(%p, %zu, %zu, %p)\n", buffer, size, count, stream);
if (!buffer || !stream) { if (!buffer || !stream) {
errno = EINVAL; errno = EINVAL;
return 0; return 0;
} }
FILE *native = resolveFileStream(stream); FILE *native = mapToHostFile(stream);
if (!native) { if (!native) {
errno = EINVAL; errno = EINVAL;
return 0; return 0;
@@ -2808,7 +2834,7 @@ namespace msvcrt {
return wstrtoul(strSource, endptr, base); return wstrtoul(strSource, endptr, base);
} }
FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){ _FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
if (!filename || !mode) return nullptr; if (!filename || !mode) return nullptr;
std::string fname_str = wideStringToString(filename); std::string fname_str = wideStringToString(filename);
@@ -2832,10 +2858,10 @@ namespace msvcrt {
return 0; return 0;
} }
int CDECL fclose(FILE* stream){ int CDECL fclose(_FILE* stream){
HOST_CONTEXT_GUARD(); HOST_CONTEXT_GUARD();
VERBOSE_LOG("fclose(%p)\n", stream); VERBOSE_LOG("fclose(%p)\n", stream);
return ::fclose(stream); return closeGuestFile(stream);
} }
int CDECL _flushall(){ int CDECL _flushall(){
@@ -2843,9 +2869,15 @@ namespace msvcrt {
DEBUG_LOG("_flushall()\n"); DEBUG_LOG("_flushall()\n");
int count = 0; int count = 0;
if (msvcrt::fflush(stdin) == 0) count++; if (::fflush(stdin) == 0) count++;
if (msvcrt::fflush(stdout) == 0) count++; if (::fflush(stdout) == 0) count++;
if (msvcrt::fflush(stderr) == 0) count++; if (::fflush(stderr) == 0) count++;
std::lock_guard lock(g_fileMutex);
for (auto &file : g_files) {
if (::fflush(file.second) == 0)
count++;
}
return count; return count;
} }

View File

@@ -7,7 +7,9 @@ using WINT_T = unsigned short;
typedef void(_CC_CDECL *_PVFV)(); typedef void(_CC_CDECL *_PVFV)();
typedef int(_CC_CDECL *_PIFV)(); typedef int(_CC_CDECL *_PIFV)();
using _onexit_t = _PIFV; typedef int(_CC_CDECL *_onexit_t)();
typedef void(_CC_CDECL *signal_handler)(int);
typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
struct _utimbuf { struct _utimbuf {
long actime; long actime;
@@ -21,31 +23,26 @@ struct _timeb {
short dstflag; short dstflag;
}; };
typedef void(_CC_CDECL *signal_handler)(int);
using FILE = struct _IO_FILE;
struct IOBProxy {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
struct lconv; struct lconv;
namespace msvcrt { namespace msvcrt {
IOBProxy *CDECL __iob_func(); extern int _commode;
IOBProxy *CDECL __p__iob(); extern int _fmode;
void CDECL setbuf(FILE *stream, char *buffer); extern char **__initenv;
extern WCHAR **__winitenv;
extern WCHAR *_wpgmptr;
extern char *_pgmptr;
extern int __mb_cur_max;
extern _FILE _iob[_IOB_ENTRIES];
_FILE *CDECL __iob_func();
_FILE *CDECL __p__iob();
void CDECL setbuf(_FILE *stream, char *buffer);
void CDECL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext); void CDECL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext);
int CDECL _fileno(FILE *stream); int CDECL _fileno(_FILE *stream);
int CDECL _getmbcp(); int CDECL _getmbcp();
unsigned int *CDECL __p___mb_cur_max(); int *CDECL __p___mb_cur_max();
int CDECL _setmbcp(int codepage); int CDECL _setmbcp(int codepage);
unsigned char *CDECL __p__mbctype(); unsigned char *CDECL __p__mbctype();
unsigned short **CDECL __p__pctype(); unsigned short **CDECL __p__pctype();
@@ -57,7 +54,7 @@ void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end); int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end);
unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask); unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask);
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask); int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask);
_PIFV CDECL _onexit(_PIFV func); _onexit_t CDECL _onexit(_onexit_t func);
int CDECL __wgetmainargs(int *wargc, WCHAR ***wargv, WCHAR ***wenv, int doWildcard, int *startInfo); int CDECL __wgetmainargs(int *wargc, WCHAR ***wargv, WCHAR ***wenv, int doWildcard, int *startInfo);
int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo); int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo);
char *CDECL getenv(const char *varname); char *CDECL getenv(const char *varname);
@@ -92,9 +89,9 @@ int CDECL_NO_CONV _snprintf(char *buffer, SIZE_T count, const char *format, ...)
int CDECL_NO_CONV sprintf(char *buffer, const char *format, ...); int CDECL_NO_CONV sprintf(char *buffer, const char *format, ...);
int CDECL_NO_CONV printf(const char *format, ...); int CDECL_NO_CONV printf(const char *format, ...);
int CDECL_NO_CONV sscanf(const char *buffer, const char *format, ...); int CDECL_NO_CONV sscanf(const char *buffer, const char *format, ...);
char *CDECL fgets(char *str, int count, FILE *stream); char *CDECL fgets(char *str, int count, _FILE *stream);
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, FILE *stream); SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag); _FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag);
int CDECL _sopen(const char *path, int oflag, int shflag, int pmode); int CDECL _sopen(const char *path, int oflag, int shflag, int pmode);
int CDECL _read(int fd, void *buffer, unsigned int count); int CDECL _read(int fd, void *buffer, unsigned int count);
int CDECL _close(int fd); int CDECL _close(int fd);
@@ -144,20 +141,20 @@ void CDECL free(void *ptr);
void *CDECL memcpy(void *dest, const void *src, SIZE_T count); void *CDECL memcpy(void *dest, const void *src, SIZE_T count);
void *CDECL memmove(void *dest, const void *src, SIZE_T count); void *CDECL memmove(void *dest, const void *src, SIZE_T count);
int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count); int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count);
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, int (*compar)(const void *, const void *)); void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
int CDECL fflush(FILE *stream); int CDECL fflush(_FILE *stream);
int CDECL_NO_CONV vfwprintf(FILE *stream, const WCHAR *format, va_list args); int CDECL_NO_CONV vfwprintf(_FILE *stream, const WCHAR *format, va_list args);
FILE *CDECL fopen(const char *filename, const char *mode); _FILE *CDECL fopen(const char *filename, const char *mode);
int CDECL _dup2(int fd1, int fd2); int CDECL _dup2(int fd1, int fd2);
int CDECL _isatty(int fd); int CDECL _isatty(int fd);
int CDECL fseek(FILE *stream, long offset, int origin); int CDECL fseek(_FILE *stream, long offset, int origin);
long CDECL ftell(FILE *stream); long CDECL ftell(_FILE *stream);
int CDECL feof(FILE *stream); int CDECL feof(_FILE *stream);
int CDECL fputws(const WCHAR *str, FILE *stream); int CDECL fputws(const WCHAR *str, _FILE *stream);
int CDECL _cputws(const WCHAR *string); int CDECL _cputws(const WCHAR *string);
WCHAR *CDECL fgetws(WCHAR *buffer, int size, FILE *stream); WCHAR *CDECL fgetws(WCHAR *buffer, int size, _FILE *stream);
WINT_T CDECL fgetwc(FILE *stream); WINT_T CDECL fgetwc(_FILE *stream);
int CDECL _wfopen_s(FILE **stream, const WCHAR *filename, const WCHAR *mode); int CDECL _wfopen_s(_FILE **stream, const WCHAR *filename, const WCHAR *mode);
int CDECL _wcsicmp(const WCHAR *lhs, const WCHAR *rhs); int CDECL _wcsicmp(const WCHAR *lhs, const WCHAR *rhs);
int CDECL _wmakepath_s(WCHAR *path, SIZE_T sizeInWords, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname, int CDECL _wmakepath_s(WCHAR *path, SIZE_T sizeInWords, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname,
const WCHAR *ext); const WCHAR *ext);
@@ -175,10 +172,10 @@ int CDECL _crt_debugger_hook(int value);
int CDECL _configthreadlocale(int mode); int CDECL _configthreadlocale(int mode);
void CDECL __setusermatherr(void *handler); void CDECL __setusermatherr(void *handler);
void CDECL _cexit(); void CDECL _cexit();
int CDECL_NO_CONV vfprintf(FILE *stream, const char *format, va_list args); int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args);
int CDECL_NO_CONV fprintf(FILE *stream, const char *format, ...); int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...);
int CDECL fputc(int ch, FILE *stream); int CDECL fputc(int ch, _FILE *stream);
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, FILE *stream); SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
char *CDECL strerror(int errnum); char *CDECL strerror(int errnum);
char *CDECL strchr(const char *str, int character); char *CDECL strchr(const char *str, int character);
struct lconv *CDECL localeconv(); struct lconv *CDECL localeconv();
@@ -220,9 +217,9 @@ int CDECL iswdigit(WINT_T w);
const WCHAR *CDECL wcschr(const WCHAR *str, WCHAR c); const WCHAR *CDECL wcschr(const WCHAR *str, WCHAR c);
const WCHAR *CDECL wcsrchr(const WCHAR *str, WCHAR c); const WCHAR *CDECL wcsrchr(const WCHAR *str, WCHAR c);
unsigned long CDECL wcstoul(const WCHAR *strSource, WCHAR **endptr, int base); unsigned long CDECL wcstoul(const WCHAR *strSource, WCHAR **endptr, int base);
FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag); _FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag);
int CDECL puts(const char *str); int CDECL puts(const char *str);
int CDECL fclose(FILE *stream); int CDECL fclose(_FILE *stream);
int CDECL _flushall(); int CDECL _flushall();
int *CDECL _errno(); int *CDECL _errno();
LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, const WCHAR *const *argv); LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, const WCHAR *const *argv);

View File

@@ -444,3 +444,19 @@ typedef struct _MEMORY_BASIC_INFORMATION {
DWORD Protect; DWORD Protect;
DWORD Type; DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
#define _IOB_ENTRIES 20
typedef struct _iobuf {
_iobuf() : _file(-1) {}
explicit _iobuf(int file) : _file(file) {}
char *_ptr = nullptr;
int _cnt = 0;
char *_base = nullptr;
int _flag = 0;
int _file;
int _charbuf = 0;
int _bufsiz = 0;
char *_tmpfname = nullptr;
} _FILE;

View File

@@ -29,14 +29,13 @@ from clang.cindex import (
Cursor, Cursor,
CursorKind, CursorKind,
Index, Index,
StorageClass,
TranslationUnit, TranslationUnit,
Type, Type,
TypeKind, TypeKind,
conf, conf,
) )
from clang.cindex import ( from clang.cindex import Type as CXType
Type as CXType,
)
# Allow libclang path to be specified via environment variable # Allow libclang path to be specified via environment variable
if "LIBCLANG_PATH" in os.environ: if "LIBCLANG_PATH" in os.environ:
@@ -123,6 +122,12 @@ class TypedefInfo:
args: List[ArgInfo] = field(default_factory=list) args: List[ArgInfo] = field(default_factory=list)
@dataclass
class VarInfo:
qualified_ns: str
name: str
def parse_tu( def parse_tu(
headers: List[str], include_dirs: List[str], target: str headers: List[str], include_dirs: List[str], target: str
) -> TranslationUnit: ) -> TranslationUnit:
@@ -338,6 +343,35 @@ def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]:
return sorted(out.values(), key=lambda t: t.name) return sorted(out.values(), key=lambda t: t.name)
def collect_variables(tu: TranslationUnit, ns_filter: Optional[str]) -> List[VarInfo]:
"""Collect extern variable declarations from the translation unit."""
want_ns = ns_filter.split("::") if ns_filter else None
out: dict[str, VarInfo] = {}
def visit(node: Cursor) -> None:
if node.kind == CursorKind.VAR_DECL:
if node.storage_class != StorageClass.EXTERN or node.is_definition():
return
ns_parts = _cursor_namespace(node)
if want_ns is not None and ns_parts != want_ns:
return
name = node.spelling
if not name:
return
out[name] = VarInfo(
qualified_ns="::".join(ns_parts),
name=name,
)
if node.kind in (CursorKind.TRANSLATION_UNIT, CursorKind.NAMESPACE):
for c in node.get_children():
visit(c)
if tu.cursor is not None:
visit(tu.cursor)
return sorted(out.values(), key=lambda v: v.name)
def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]): def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
if isinstance(f, TypedefInfo): if isinstance(f, TypedefInfo):
# Host-to-guest # Host-to-guest
@@ -543,7 +577,10 @@ def emit_host_to_guest_thunks(
def emit_header_mapping( def emit_header_mapping(
dll: str, funcs: Iterable[FuncInfo], typedefs: Iterable[TypedefInfo] dll: str,
funcs: Iterable[FuncInfo],
typedefs: Iterable[TypedefInfo],
variables: Iterable[VarInfo],
) -> str: ) -> str:
guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H" guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H"
lines: List[str] = [] lines: List[str] = []
@@ -616,6 +653,11 @@ def emit_header_mapping(
lines.append( lines.append(
f'\tif (strcmp(name, "{f.name}") == 0) return (void*)&thunk_{dll}_{f.name};' f'\tif (strcmp(name, "{f.name}") == 0) return (void*)&thunk_{dll}_{f.name};'
) )
for v in variables:
qualified = f"{v.qualified_ns}::{v.name}" if v.qualified_ns else v.name
lines.append(
f'\tif (strcmp(name, "{v.name}") == 0) return (void*)&{qualified};'
)
lines.append("\treturn NULL;") lines.append("\treturn NULL;")
lines.append("}") lines.append("}")
@@ -644,9 +686,10 @@ def main() -> int:
tu = parse_tu(args.headers, args.incs, target) tu = parse_tu(args.headers, args.incs, target)
funcs = collect_functions(tu, args.ns) funcs = collect_functions(tu, args.ns)
typedefs = collect_typedefs(tu) typedefs = collect_typedefs(tu)
variables = collect_variables(tu, args.ns)
if not funcs and not typedefs: if not funcs and not typedefs and not variables:
sys.stderr.write("No functions or typedefs found for generation.\n") sys.stderr.write("No functions, typedefs, or variables found for generation.\n")
return 1 return 1
lines: List[str] = [] lines: List[str] = []
@@ -659,7 +702,7 @@ def main() -> int:
emit_host_to_guest_thunks(lines, typedefs) emit_host_to_guest_thunks(lines, typedefs)
asm = "\n".join(lines) + "\n" asm = "\n".join(lines) + "\n"
hdr = emit_header_mapping(args.dll, funcs, typedefs) hdr = emit_header_mapping(args.dll, funcs, typedefs, variables)
args.out_asm.parent.mkdir(parents=True, exist_ok=True) args.out_asm.parent.mkdir(parents=True, exist_ok=True)
args.out_hdr.parent.mkdir(parents=True, exist_ok=True) args.out_hdr.parent.mkdir(parents=True, exist_ok=True)