Skip to content

Commit d3d4801

Browse files
committed
Support small TLS directories & implement GlobalMemoryStatus
1 parent 0f12807 commit d3d4801

3 files changed

Lines changed: 150 additions & 10 deletions

File tree

dll/kernel32/winbase.cpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424
#include <string>
2525
#include <sys/mman.h>
2626
#include <sys/statvfs.h>
27+
#if defined(__APPLE__)
28+
#include <mach/mach.h>
29+
#include <sys/sysctl.h>
30+
#elif defined(__linux__)
31+
#include <sys/sysinfo.h>
32+
#endif
2733
#include <system_error>
2834
#include <unordered_map>
2935
#include <vector>
@@ -42,6 +48,71 @@ constexpr ATOM kMaxIntegerAtom = 0xBFFF;
4248
constexpr ATOM kMinStringAtom = 0xC000;
4349
constexpr ATOM kMaxStringAtom = 0xFFFF;
4450

51+
SIZE_T clampToSizeT(uint64_t value) {
52+
constexpr uint64_t kMaxSizeT = static_cast<uint64_t>(std::numeric_limits<SIZE_T>::max());
53+
return value > kMaxSizeT ? static_cast<SIZE_T>(kMaxSizeT) : static_cast<SIZE_T>(value);
54+
}
55+
56+
struct MemorySnapshot {
57+
uint64_t totalPhys = 0;
58+
uint64_t availPhys = 0;
59+
uint64_t totalPageFile = 0;
60+
uint64_t availPageFile = 0;
61+
};
62+
63+
bool queryHostMemory(MemorySnapshot &out) {
64+
#if defined(__linux__)
65+
struct sysinfo info {};
66+
if (sysinfo(&info) != 0) {
67+
return false;
68+
}
69+
const uint64_t unit = info.mem_unit ? static_cast<uint64_t>(info.mem_unit) : 1;
70+
out.totalPhys = static_cast<uint64_t>(info.totalram) * unit;
71+
out.availPhys = static_cast<uint64_t>(info.freeram) * unit;
72+
out.totalPageFile = (static_cast<uint64_t>(info.totalram) + static_cast<uint64_t>(info.totalswap)) * unit;
73+
out.availPageFile = (static_cast<uint64_t>(info.freeram) + static_cast<uint64_t>(info.freeswap)) * unit;
74+
if (info.bufferram > 0) {
75+
uint64_t buffers = static_cast<uint64_t>(info.bufferram) * unit;
76+
out.availPhys += buffers;
77+
out.availPageFile += buffers;
78+
}
79+
return true;
80+
#elif defined(__APPLE__)
81+
uint64_t totalPhys = 0;
82+
size_t totalPhysSize = sizeof(totalPhys);
83+
if (sysctlbyname("hw.memsize", &totalPhys, &totalPhysSize, nullptr, 0) != 0) {
84+
return false;
85+
}
86+
vm_size_t pageSize = 0;
87+
if (host_page_size(mach_host_self(), &pageSize) != KERN_SUCCESS || pageSize == 0) {
88+
return false;
89+
}
90+
vm_statistics64_data_t vmstat {};
91+
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
92+
if (host_statistics64(mach_host_self(), HOST_VM_INFO64, reinterpret_cast<host_info64_t>(&vmstat), &count) !=
93+
KERN_SUCCESS) {
94+
return false;
95+
}
96+
uint64_t freePages = static_cast<uint64_t>(vmstat.free_count) + static_cast<uint64_t>(vmstat.inactive_count) +
97+
static_cast<uint64_t>(vmstat.speculative_count);
98+
out.totalPhys = totalPhys;
99+
out.availPhys = freePages * static_cast<uint64_t>(pageSize);
100+
101+
struct xsw_usage swap {};
102+
size_t swapSize = sizeof(swap);
103+
if (sysctlbyname("vm.swapusage", &swap, &swapSize, nullptr, 0) == 0 && swapSize == sizeof(swap)) {
104+
out.totalPageFile = swap.xsu_total;
105+
out.availPageFile = swap.xsu_avail;
106+
} else {
107+
out.totalPageFile = totalPhys;
108+
out.availPageFile = out.availPhys;
109+
}
110+
return true;
111+
#else
112+
return false;
113+
#endif
114+
}
115+
45116
struct AtomData {
46117
uint16_t refCount = 0;
47118
std::string original;
@@ -780,6 +851,54 @@ UINT WINAPI GlobalFlags(HGLOBAL hMem) {
780851
return 0;
781852
}
782853

854+
void WINAPI GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer) {
855+
HOST_CONTEXT_GUARD();
856+
DEBUG_LOG("GlobalMemoryStatus(%p)\n", lpBuffer);
857+
if (!lpBuffer) {
858+
return;
859+
}
860+
861+
std::memset(lpBuffer, 0, sizeof(*lpBuffer));
862+
lpBuffer->dwLength = sizeof(*lpBuffer);
863+
864+
MemorySnapshot snapshot;
865+
if (!queryHostMemory(snapshot)) {
866+
return;
867+
}
868+
869+
uint64_t totalPhys = snapshot.totalPhys;
870+
uint64_t availPhys = snapshot.availPhys;
871+
uint64_t totalPageFile = snapshot.totalPageFile;
872+
uint64_t availPageFile = snapshot.availPageFile;
873+
874+
constexpr uint64_t kMinAppAddr = 0x00010000ULL;
875+
constexpr uint64_t kMaxAppAddr = 0x7FFEFFFFULL;
876+
uint64_t totalVirtual = kMaxAppAddr - kMinAppAddr + 1;
877+
uint64_t availVirtual = totalVirtual;
878+
879+
constexpr uint64_t kMaxLegacy = static_cast<uint64_t>(std::numeric_limits<LONG>::max());
880+
totalPhys = std::min(totalPhys, kMaxLegacy);
881+
availPhys = std::min(availPhys, kMaxLegacy);
882+
totalVirtual = std::min(totalVirtual, kMaxLegacy);
883+
availVirtual = std::min(availVirtual, kMaxLegacy);
884+
availPhys = std::min(availPhys, totalPhys);
885+
availPageFile = std::min(availPageFile, totalPageFile);
886+
availVirtual = std::min(availVirtual, totalVirtual);
887+
888+
if (totalPhys > 0) {
889+
uint64_t used = totalPhys > availPhys ? totalPhys - availPhys : 0;
890+
uint64_t load = (used * 100) / totalPhys;
891+
lpBuffer->dwMemoryLoad = static_cast<DWORD>(std::min<uint64_t>(load, 100));
892+
}
893+
894+
lpBuffer->dwTotalPhys = clampToSizeT(totalPhys);
895+
lpBuffer->dwAvailPhys = clampToSizeT(availPhys);
896+
lpBuffer->dwTotalPageFile = clampToSizeT(totalPageFile);
897+
lpBuffer->dwAvailPageFile = clampToSizeT(availPageFile);
898+
lpBuffer->dwTotalVirtual = clampToSizeT(totalVirtual);
899+
lpBuffer->dwAvailVirtual = clampToSizeT(availVirtual);
900+
}
901+
783902
HLOCAL WINAPI LocalAlloc(UINT uFlags, SIZE_T uBytes) {
784903
HOST_CONTEXT_GUARD();
785904
VERBOSE_LOG("LocalAlloc(%x, %zu)\n", uFlags, static_cast<size_t>(uBytes));

dll/kernel32/winbase.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ struct ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT {
5757
ULONG Offset;
5858
};
5959

60+
struct MEMORYSTATUS {
61+
DWORD dwLength;
62+
DWORD dwMemoryLoad;
63+
SIZE_T dwTotalPhys;
64+
SIZE_T dwAvailPhys;
65+
SIZE_T dwTotalPageFile;
66+
SIZE_T dwAvailPageFile;
67+
SIZE_T dwTotalVirtual;
68+
SIZE_T dwAvailVirtual;
69+
};
70+
71+
using LPMEMORYSTATUS = MEMORYSTATUS *;
72+
6073
namespace kernel32 {
6174

6275
BOOL WINAPI IsBadReadPtr(LPCVOID lp, UINT_PTR ucb);
@@ -86,6 +99,7 @@ HGLOBAL WINAPI GlobalAlloc(UINT uFlags, SIZE_T dwBytes);
8699
HGLOBAL WINAPI GlobalFree(HGLOBAL hMem);
87100
HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags);
88101
UINT WINAPI GlobalFlags(HGLOBAL hMem);
102+
void WINAPI GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer);
89103

90104
HLOCAL WINAPI LocalAlloc(UINT uFlags, SIZE_T uBytes);
91105
HLOCAL WINAPI LocalFree(HLOCAL hMem);

src/modules.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <algorithm>
1616
#include <array>
1717
#include <climits>
18+
#include <cstddef>
1819
#include <cstdio>
1920
#include <cstdlib>
2021
#include <cstring>
@@ -281,6 +282,8 @@ struct ImageTlsDirectory32 {
281282
uint32_t Characteristics;
282283
};
283284

285+
constexpr size_t kMinTlsDirectorySize = offsetof(ImageTlsDirectory32, SizeOfZeroFill);
286+
284287
uintptr_t resolveModuleAddress(const wibo::Executable &exec, uintptr_t address) {
285288
if (address == 0) {
286289
return 0;
@@ -918,24 +921,28 @@ bool initializeModuleTls(ModuleInfo &module) {
918921
return true;
919922
}
920923
Executable &exec = *module.executable;
921-
if (exec.tlsDirectoryRVA == 0 || exec.tlsDirectorySize < sizeof(ImageTlsDirectory32)) {
924+
if (exec.tlsDirectoryRVA == 0 || exec.tlsDirectorySize < kMinTlsDirectorySize) {
922925
return true;
923926
}
924-
auto tlsDirectory = exec.fromRVA<ImageTlsDirectory32>(exec.tlsDirectoryRVA);
925-
if (!tlsDirectory) {
927+
auto *tlsDirectoryRaw = exec.fromRVA<uint8_t>(exec.tlsDirectoryRVA);
928+
if (!tlsDirectoryRaw) {
926929
return false;
927930
}
931+
ImageTlsDirectory32 tlsDirectory{};
932+
// TLS directory may be smaller than ImageTlsDirectory32; remaining fields are zero-initialized
933+
size_t copySize = std::min<size_t>(exec.tlsDirectorySize, sizeof(tlsDirectory));
934+
std::memcpy(&tlsDirectory, tlsDirectoryRaw, copySize);
928935

929936
auto &info = module.tlsInfo;
930-
info.templateSize = (tlsDirectory->EndAddressOfRawData > tlsDirectory->StartAddressOfRawData)
931-
? tlsDirectory->EndAddressOfRawData - tlsDirectory->StartAddressOfRawData
937+
info.templateSize = (tlsDirectory.EndAddressOfRawData > tlsDirectory.StartAddressOfRawData)
938+
? tlsDirectory.EndAddressOfRawData - tlsDirectory.StartAddressOfRawData
932939
: 0;
933-
info.zeroFillSize = tlsDirectory->SizeOfZeroFill;
934-
info.characteristics = tlsDirectory->Characteristics;
935-
info.templateData = reinterpret_cast<uint8_t *>(resolveModuleAddress(exec, tlsDirectory->StartAddressOfRawData));
936-
info.indexLocation = reinterpret_cast<DWORD *>(resolveModuleAddress(exec, tlsDirectory->AddressOfIndex));
940+
info.zeroFillSize = tlsDirectory.SizeOfZeroFill;
941+
info.characteristics = tlsDirectory.Characteristics;
942+
info.templateData = reinterpret_cast<uint8_t *>(resolveModuleAddress(exec, tlsDirectory.StartAddressOfRawData));
943+
info.indexLocation = reinterpret_cast<DWORD *>(resolveModuleAddress(exec, tlsDirectory.AddressOfIndex));
937944
info.callbacks.clear();
938-
uintptr_t callbacksArray = resolveModuleAddress(exec, tlsDirectory->AddressOfCallBacks);
945+
uintptr_t callbacksArray = resolveModuleAddress(exec, tlsDirectory.AddressOfCallBacks);
939946
if (callbacksArray) {
940947
auto callbackPtr = reinterpret_cast<GUEST_PTR *>(callbacksArray);
941948
while (callbackPtr && *callbackPtr) {

0 commit comments

Comments
 (0)