ReXGlue SDK
Loading...
Searching...
No Matches
shim.h
Go to the documentation of this file.
1
10
11#pragma once
12
13#include <array>
14#include <string_view>
15
16#include <rex/bit.h>
17#include <rex/types.h>
18
19namespace rex::kernel::shim {
20
21enum class Group : u8 {
22 kFile,
24 kMemory,
27 kDebug,
29};
30
31enum class Flag : u8 {
32 kNone = 0,
33 kStub = 1 << 0,
34 kRequiresHeap = 1 << 1,
35};
36
37} // namespace rex::kernel::shim
38
39template <>
40inline constexpr bool rex::is_flags_enum<rex::kernel::shim::Flag> = true;
41
42namespace rex::kernel::shim {
43
45 Group id;
46 std::string_view name;
47 bool atomic;
48 std::string_view summary;
49};
50
51struct Entry {
52 std::string_view name;
53 Group group;
54 Flag flags;
55 std::string_view description;
56};
57
58inline constexpr std::array<GroupTraits, 7> kGroups = {{
59 {Group::kFile, "file", false, "File I/O backed by the filesystem module"},
60 {Group::kHeap, "heap", true, "The shim heap, all 4 routines are required together"},
61 {Group::kMemory, "memory", false, "Memory copy and fill routines"},
62 {Group::kString, "string", false, "C, Win32 and UTF-16 string routines"},
63 {Group::kMath, "math", false, "Floating point math and text conversion routines"},
64 {Group::kDebug, "debug", false, "Debug output routines"},
65 {Group::kThreading, "threading", false, "Fiber routines"},
66}};
67
68inline constexpr std::array<Entry, 69> kRegistry = {{
69 {"CreateFileA", Group::kFile, Flag::kNone, "Opens or creates a file"},
70 {"ReadFile", Group::kFile, Flag::kNone, "Reads from an open file handle"},
71 {"WriteFile", Group::kFile, Flag::kNone, "Writes to an open file handle"},
72 {"SetFilePointer", Group::kFile, Flag::kNone, "Moves the file position with a 32 bit distance"},
73 {"GetFileSize", Group::kFile, Flag::kNone, "Returns the low 32 bits of a file size"},
74 {"GetFileSizeEx", Group::kFile, Flag::kNone, "Returns the 64 bit file size"},
75 {"SetEndOfFile", Group::kFile, Flag::kNone, "Truncates a file at the current position"},
76 {"FlushFileBuffers", Group::kFile, Flag::kStub, "Returns success without flushing the file"},
77 {"DeleteFileA", Group::kFile, Flag::kNone, "Deletes a file"},
78 {"CloseHandle", Group::kFile, Flag::kNone, "Closes a file or search handle"},
79 {"FindFirstFileA", Group::kFile, Flag::kNone, "Begins a directory search"},
80 {"FindNextFileA", Group::kFile, Flag::kNone, "Returns the next directory search result"},
81 {"FindClose", Group::kFile, Flag::kNone, "Ends a directory search"},
82 {"CreateDirectoryA", Group::kFile, Flag::kNone, "Creates a directory"},
83 {"MoveFileA", Group::kFile, Flag::kNone, "Renames a file or directory"},
84 {"SetFileAttributesA", Group::kFile, Flag::kStub, "Returns success without setting attributes"},
85 {"GetFileAttributesA", Group::kFile, Flag::kNone, "Returns file attributes"},
86 {"GetFileAttributesExA", Group::kFile, Flag::kNone, "Returns extended file attribute data"},
87 {"SetFilePointerEx", Group::kFile, Flag::kNone,
88 "Moves the file position with a 64 bit distance"},
89 {"SetFileTime", Group::kFile, Flag::kStub, "Returns success without setting the timestamps"},
90 {"CompareFileTime", Group::kFile, Flag::kNone, "Compares 2 file times"},
91 {"CopyFileA", Group::kFile, Flag::kNone, "Copies a file"},
92 {"RemoveDirectoryA", Group::kFile, Flag::kNone, "Removes an empty directory"},
93 {"GetFileType", Group::kFile, Flag::kNone, "Returns the type of a file handle"},
94 {"RtlAllocateHeap", Group::kHeap, Flag::kRequiresHeap,
95 "Allocates memory, honors the zero flag"},
96 {"RtlFreeHeap", Group::kHeap, Flag::kRequiresHeap, "Frees an allocation"},
97 {"RtlSizeHeap", Group::kHeap, Flag::kRequiresHeap,
98 "Returns the requested size of an allocation"},
99 {"RtlReAllocateHeap", Group::kHeap, Flag::kRequiresHeap,
100 "Resizes an allocation in place or by copy"},
101 {"memcpy", Group::kMemory, Flag::kNone, "Copies memory"},
102 {"memmove", Group::kMemory, Flag::kNone, "Copies overlapping memory"},
103 {"memset", Group::kMemory, Flag::kNone, "Fills memory"},
104 {"memchr", Group::kMemory, Flag::kNone, "Finds a byte in memory"},
105 {"XMemCpy", Group::kMemory, Flag::kNone, "Copies memory"},
106 {"XMemSet", Group::kMemory, Flag::kNone, "Fills memory"},
107 {"XMemSet128", Group::kMemory, Flag::kNone, "Fills memory with a byte value"},
108 {"memset_vmx", Group::kMemory, Flag::kNone, "Fills memory with a byte value"},
109 {"memcpy_s", Group::kMemory, Flag::kNone, "Copies memory with a size check"},
110 {"memmove_s", Group::kMemory, Flag::kNone, "Copies overlapping memory with a size check"},
111 {"strncmp", Group::kString, Flag::kNone, "Compares 2 strings up to a length"},
112 {"strncpy", Group::kString, Flag::kNone, "Copies a string up to a length"},
113 {"strchr", Group::kString, Flag::kNone, "Finds a character in a string"},
114 {"strstr", Group::kString, Flag::kNone, "Finds a substring"},
115 {"strrchr", Group::kString, Flag::kNone, "Finds the last occurrence of a character"},
116 {"strtok", Group::kString, Flag::kNone, "Splits a string into tokens"},
117 {"_stricmp", Group::kString, Flag::kNone, "Compares 2 strings ignoring case"},
118 {"strcpy_s", Group::kString, Flag::kNone, "Copies a string with a size check"},
119 {"lstrlenA", Group::kString, Flag::kNone, "Returns the length of a string"},
120 {"lstrcpyA", Group::kString, Flag::kNone, "Copies a string"},
121 {"lstrcpynA", Group::kString, Flag::kNone, "Copies a string up to a length"},
122 {"lstrcatA", Group::kString, Flag::kNone, "Appends a string"},
123 {"lstrcmpiA", Group::kString, Flag::kNone, "Compares 2 strings ignoring case"},
124 {"wcslen", Group::kString, Flag::kNone, "Returns the length of a UTF-16 string"},
125 {"wcscmp", Group::kString, Flag::kNone, "Compares 2 UTF-16 strings"},
126 {"wcsncmp", Group::kString, Flag::kNone, "Compares 2 UTF-16 strings up to a length"},
127 {"wcscoll", Group::kString, Flag::kNone, "Compares 2 UTF-16 strings by collation"},
128 {"wcschr", Group::kString, Flag::kNone, "Finds a character in a UTF-16 string"},
129 {"wcsrchr", Group::kString, Flag::kNone, "Finds the last occurrence in a UTF-16 string"},
130 {"wcscpy", Group::kString, Flag::kNone, "Copies a UTF-16 string"},
131 {"wcsncpy", Group::kString, Flag::kNone, "Copies a UTF-16 string up to a length"},
132 {"wcsncpy_s", Group::kString, Flag::kNone, "Copies a UTF-16 string with a size check"},
133 {"wcsstr", Group::kString, Flag::kNone, "Finds a UTF-16 substring"},
134 {"atan2", Group::kMath, Flag::kNone, "Returns the arc tangent of y over x"},
135 {"atof", Group::kMath, Flag::kNone,
136 "Parses a floating point number, independent of the locale"},
137 {"DebugPrint", Group::kDebug, Flag::kNone,
138 "Logs a formatted debug message at Debug level, Shift-JIS converted to UTF-8"},
139 {"ConvertThreadToFiber", Group::kThreading, Flag::kNone,
140 "Turns the calling thread into a fiber"},
141 {"ConvertFiberToThread", Group::kThreading, Flag::kNone,
142 "Turns the calling fiber back into a thread"},
143 {"CreateFiber", Group::kThreading, Flag::kNone, "Creates a fiber"},
144 {"DeleteFiber", Group::kThreading, Flag::kNone, "Deletes a fiber"},
145 {"SwitchToFiber", Group::kThreading, Flag::kNone, "Switches to another fiber"},
146}};
147
152constexpr const Entry* Find(std::string_view name) {
153 for (const Entry& entry : kRegistry) {
154 if (entry.name == name) {
155 return &entry;
156 }
157 }
158 return nullptr;
159}
160
161constexpr bool IsRegistered(std::string_view name) {
162 return Find(name) != nullptr;
163}
164
165constexpr const GroupTraits& TraitsOf(Group group) {
166 for (const GroupTraits& traits : kGroups) {
167 if (traits.id == group) {
168 return traits;
169 }
170 }
171 return kGroups[0];
172}
173
174namespace detail {
175
176constexpr bool HasDuplicateNames() {
177 for (size_t i = 0; i < kRegistry.size(); ++i) {
178 for (size_t j = i + 1; j < kRegistry.size(); ++j) {
179 if (kRegistry[i].name == kRegistry[j].name) {
180 return true;
181 }
182 }
183 }
184 return false;
185}
186
187constexpr bool AtomicEntriesRequireHeap() {
188 for (const Entry& entry : kRegistry) {
189 if (TraitsOf(entry.group).atomic && !HasFlags(entry.flags, Flag::kRequiresHeap)) {
190 return false;
191 }
192 }
193 return true;
194}
195
196constexpr bool IsEveryGroupListed() {
197 for (const Entry& entry : kRegistry) {
198 if (TraitsOf(entry.group).id != entry.group) {
199 return false;
200 }
201 }
202 return true;
203}
204
205} // namespace detail
206
207static_assert(!detail::HasDuplicateNames(), "shim registry holds a duplicate name");
208static_assert(detail::AtomicEntriesRequireHeap(), "an atomic group entry lacks RequiresHeap");
209static_assert(detail::IsEveryGroupListed(), "a shim entry names a group missing from kGroups");
210
211} // namespace rex::kernel::shim
Definition guest_allocator.h:27
Group
Definition shim.h:21
@ kThreading
Definition shim.h:28
@ kFile
Definition shim.h:22
@ kString
Definition shim.h:25
@ kHeap
Definition shim.h:23
@ kMath
Definition shim.h:26
Flag
Definition shim.h:31
@ kRequiresHeap
Definition shim.h:34
@ kStub
Definition shim.h:33
constexpr const Entry * Find(std::string_view name)
Definition shim.h:152
@ kHeap
Definition guest_allocator.h:39
constexpr bool is_flags_enum
Definition bit.h:422
constexpr bool HasFlags(E value, E flags)
Definition bit.h:483
Definition shim.h:51
std::string_view name
Definition shim.h:52
Definition shim.h:44
bool atomic
Definition shim.h:47
std::string_view name
Definition shim.h:46
Integer types, byte order wrappers and size literals.