activity_sdk_decode_plans_internal.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. #pragma once
  2. #include <Windows.h>
  3. #include <array>
  4. #include <cstddef>
  5. #include <cstdint>
  6. #include <cstring>
  7. #include <map>
  8. #include <span>
  9. #include <vector>
  10. #include "../../../middleware/content/packages/reader/reader.h"
  11. #include "../../../middleware/crypto/sha256.h"
  12. #include "activity_sdk_decode_plans.h"
  13. namespace sunrise::client::content::activity::sdk_generation::decode_plans::internal {
  14. namespace reader = middleware::content::packages::reader;
  15. using Digest = middleware::crypto::sha256::Digest;
  16. /** Absent handle or index in package and reflection data. */
  17. inline constexpr std::uint32_t kAbsent = 0xFFFFFFFFU;
  18. /** Reflection record block chain marker and the generic-argument marker before it. */
  19. inline constexpr std::uint32_t kReflectionMarker = 0x80800050U;
  20. inline constexpr std::uint32_t kGenericMarker = 0x8080001DU;
  21. /** Reflection block classes: field codec, property list, method list, empty tail. */
  22. inline constexpr std::uint32_t kCodecBlock = 0x8080010AU;
  23. inline constexpr std::uint32_t kPropertyBlock = 0x8080012FU;
  24. inline constexpr std::uint32_t kMethodBlock = 0x8080010DU;
  25. inline constexpr std::uint32_t kTailBlock = 0x8080004CU;
  26. /** Generic container kinds a property may declare. */
  27. inline constexpr std::uint32_t kGenericSimple = 0x80809C37U;
  28. inline constexpr std::uint32_t kGenericDynamicA = 0x80809FBAU;
  29. inline constexpr std::uint32_t kGenericDynamicB = 0x80809C38U;
  30. inline constexpr std::uint32_t kDynamicDeclared = 0x80809FBBU;
  31. inline constexpr std::uint32_t kGenericInline = 0x80809FFCU;
  32. inline constexpr std::uint32_t kGenericCounted = 0x80809ED8U;
  33. /** Package classes: the array marker, a selection child row, metadata, and a selection. */
  34. inline constexpr std::uint32_t kArrayMarker = 0x80809FBDU;
  35. inline constexpr std::uint32_t kSelectionChildClass = 0x80808852U;
  36. inline constexpr std::uint32_t kPackageMetadataClass = 0x80800000U;
  37. inline constexpr std::uint32_t kSelectionClass = 0x80809BBBU;
  38. /** Metadata kinds that select a plan branch: plain value and generic container. */
  39. inline constexpr std::uint8_t kKindValue = 1;
  40. inline constexpr std::uint8_t kKindContainer = 11;
  41. /** Field type code of a nested schema; codes above 63 have no primitive size. */
  42. inline constexpr std::uint8_t kTypeNested = 1;
  43. inline constexpr std::uint8_t kTypeLimit = 64;
  44. /** Capacities the runtime decoder shares with the compiler. */
  45. inline constexpr std::size_t kMaximumDepth = 32;
  46. inline constexpr std::size_t kMaximumSteps = 65536;
  47. inline constexpr std::uint32_t kMaximumRepeat = 16384;
  48. inline constexpr std::uint32_t kMaximumSectionCount = 65536;
  49. inline constexpr std::uint64_t kMaximumArrayCount = 0x100000U;
  50. /** Stride of one codec field descriptor. */
  51. inline constexpr std::size_t kFieldRowSize = 40;
  52. /** Candidate offsets of the block chain marker inside a reflection record. */
  53. inline constexpr std::array<std::uint32_t, 4> kMarkerOffsets{0x58, 0x60, 0x68, 0x70};
  54. /** Header size and row stride of each reflection block class. */
  55. struct BlockLayout final {
  56. std::uint32_t header{};
  57. std::uint32_t stride{};
  58. };
  59. /**
  60. * Looks up the header size and row stride of one reflection block class.
  61. * @return False for an unknown block class.
  62. */
  63. [[nodiscard]] inline bool block_layout(std::uint32_t kind, BlockLayout& output) noexcept {
  64. switch (kind) {
  65. case kCodecBlock:
  66. output = {0x28, 0x28};
  67. return true;
  68. case kPropertyBlock:
  69. output = {0x20, 0x0C};
  70. return true;
  71. case kMethodBlock:
  72. output = {0x10, 0x08};
  73. return true;
  74. case kTailBlock:
  75. output = {0x18, 0x00};
  76. return true;
  77. default:
  78. return false;
  79. }
  80. }
  81. /** Copies one unaligned value. @return False when it does not fit inside `bytes`. */
  82. template <typename T>
  83. [[nodiscard]] bool read_at(std::span<const std::byte> bytes, std::size_t at, T& value) noexcept {
  84. if (at > bytes.size() || bytes.size() - at < sizeof(T)) {
  85. return false;
  86. }
  87. std::memcpy(&value, bytes.data() + at, sizeof(T));
  88. return true;
  89. }
  90. /** One codec field descriptor in reflection or package layout. */
  91. struct Field final {
  92. std::uint32_t offset{};
  93. std::uint32_t alternate{};
  94. std::uint32_t bit{};
  95. float half{};
  96. std::uint8_t type{};
  97. std::uint8_t presence{};
  98. std::uint16_t parameter2{};
  99. std::uint32_t nested{};
  100. std::int32_t bias{};
  101. std::int32_t width{};
  102. std::uint32_t parameter3{};
  103. std::uint32_t parameter4{};
  104. };
  105. /** One field codec block. */
  106. struct Codec final {
  107. bool present{};
  108. std::uint32_t original{};
  109. std::uint32_t serialized{};
  110. std::uint32_t flags{};
  111. std::uint32_t array{};
  112. std::vector<Field> fields{};
  113. };
  114. /** One declared property: name hash, member type handle, byte offset. */
  115. struct Property final {
  116. std::uint32_t nameHash{};
  117. std::uint32_t memberType{};
  118. std::uint32_t byteOffset{};
  119. };
  120. /** One reflection or package metadata record. */
  121. struct Metadata final {
  122. bool package{};
  123. std::uint32_t size{};
  124. std::uint8_t alignment{};
  125. std::uint8_t kind{};
  126. bool hasGeneric{};
  127. std::uint32_t generic{};
  128. Codec codec{};
  129. bool hasProperties{};
  130. Property base{};
  131. std::vector<Property> properties{};
  132. };
  133. /** One schema row of the cache: handle, serialized size, first field value, field count. */
  134. struct SchemaRow final {
  135. std::uint32_t handle{};
  136. std::uint32_t size{};
  137. std::uint32_t first{};
  138. std::uint32_t count{};
  139. };
  140. /**
  141. * The executable's reflection records and slot index.
  142. * The shipped file is packed and its slot table exists only in memory, so a live build reads the
  143. * mapped module and hashes the file; an offline build reads and hashes an unpacked dump.
  144. */
  145. class Image final {
  146. public:
  147. Image() = default;
  148. Image(const Image&) = delete;
  149. Image& operator=(const Image&) = delete;
  150. ~Image() noexcept;
  151. /** Maps the file at `path`; a non-null `module` base makes the reads come from memory. */
  152. [[nodiscard]] Status open(const wchar_t* path, const void* module) noexcept;
  153. /** @return The whole file on disk, for the evidence digest. */
  154. [[nodiscard]] std::span<const std::byte> file() const noexcept;
  155. /** @return The bytes the reflection reads go through: the file or the mapped module. */
  156. [[nodiscard]] std::span<const std::byte> bytes() const noexcept;
  157. /** Bound handle to reflection record address, first slot wins. */
  158. [[nodiscard]] const std::map<std::uint32_t, std::uint64_t>& slots() const noexcept {
  159. return slots_;
  160. }
  161. /** Address of the 64-entry primitive size table, one u32 per field type code. */
  162. [[nodiscard]] std::uint64_t primitive_sizes() const noexcept {
  163. return primitiveSizes_;
  164. }
  165. [[nodiscard]] bool u8(std::uint64_t address, std::uint8_t& value) const noexcept;
  166. [[nodiscard]] bool u16(std::uint64_t address, std::uint16_t& value) const noexcept;
  167. [[nodiscard]] bool u32(std::uint64_t address, std::uint32_t& value) const noexcept;
  168. [[nodiscard]] bool i32(std::uint64_t address, std::int32_t& value) const noexcept;
  169. [[nodiscard]] bool f32(std::uint64_t address, float& value) const noexcept;
  170. private:
  171. struct Section final {
  172. std::uint64_t virtualAddress{};
  173. std::uint64_t virtualSize{};
  174. std::uint64_t rawOffset{};
  175. std::uint64_t rawSize{};
  176. bool data{};
  177. bool code{};
  178. };
  179. [[nodiscard]] bool
  180. offset(std::uint64_t address, std::size_t size, std::size_t& at) const noexcept;
  181. [[nodiscard]] bool parse_headers(bool mapped) noexcept;
  182. [[nodiscard]] bool index_slots() noexcept;
  183. [[nodiscard]] bool resolve_primitive_sizes() noexcept;
  184. HANDLE file_{INVALID_HANDLE_VALUE};
  185. HANDLE mapping_{};
  186. const std::byte* view_{};
  187. std::size_t viewSize_{};
  188. /** Read source: the file view, or the module memory with its SizeOfImage. */
  189. const std::byte* data_{};
  190. std::size_t size_{};
  191. std::uint64_t imageBase_{};
  192. std::uint64_t vmp0Low_{};
  193. std::uint64_t vmp0High_{};
  194. std::uint64_t primitiveSizes_{};
  195. std::vector<Section> sections_{};
  196. std::map<std::uint32_t, std::uint64_t> slots_{};
  197. };
  198. /** Metadata records read so far, plus the package blob digests the evidence needs. */
  199. class Store final {
  200. public:
  201. Store(const Image& image, const reader::Source& source, reader::Scratch& scratch) noexcept
  202. : image_(image), source_(source), scratch_(scratch) {}
  203. /** @return The record, or null with the failure named in `error`. */
  204. [[nodiscard]] const Metadata* get(std::uint32_t handle, const char*& error) noexcept;
  205. [[nodiscard]] const Image& image() const noexcept {
  206. return image_;
  207. }
  208. [[nodiscard]] std::map<std::uint32_t, Digest>& package_hashes() noexcept {
  209. return packageHashes_;
  210. }
  211. [[nodiscard]] const std::map<std::uint32_t, Metadata>& entries() const noexcept {
  212. return entries_;
  213. }
  214. [[nodiscard]] bool read_package(std::uint32_t tag,
  215. std::uint32_t expectedClass,
  216. std::vector<std::byte>& output) noexcept;
  217. private:
  218. const Image& image_;
  219. const reader::Source& source_;
  220. reader::Scratch& scratch_;
  221. std::map<std::uint32_t, Metadata> entries_{};
  222. std::map<std::uint32_t, Digest> packageHashes_{};
  223. };
  224. /** One compiled plan entry in cache row order. */
  225. struct PlanEntry final {
  226. std::uint32_t schemaHandle{};
  227. std::uint32_t repeatCount{};
  228. std::uint32_t guardBit{};
  229. std::uint32_t firstFieldBit{};
  230. std::uint32_t fieldBitStride{};
  231. };
  232. /** One compiled component and selection pair. */
  233. struct Plan final {
  234. std::uint32_t component{};
  235. std::uint32_t schemaTag{};
  236. std::vector<PlanEntry> entries{};
  237. std::uint32_t bitmapBits{};
  238. bool active{};
  239. };
  240. /** Parses one bound reflection record at `address` for the compiler. */
  241. [[nodiscard]] bool parse_native(const Image& image,
  242. std::uint64_t address,
  243. Metadata& output,
  244. const char*& error) noexcept;
  245. /** Parses one package metadata blob for the compiler. */
  246. [[nodiscard]] bool parse_package(std::uint32_t handle,
  247. std::span<const std::byte> blob,
  248. Metadata& output,
  249. const char*& error) noexcept;
  250. /** Resolves the presence bit guarding `offset` inside `handle`; -1 when no field covers it. */
  251. [[nodiscard]] bool property_guard(Store& store,
  252. std::uint32_t handle,
  253. std::uint64_t offset,
  254. std::int64_t& guard,
  255. const char*& error) noexcept;
  256. /** Compiles one selection blob against its component's reflection metadata. */
  257. [[nodiscard]] bool compile(Store& store,
  258. std::uint32_t component,
  259. std::span<const std::byte> blob,
  260. Plan& output,
  261. const char*& error) noexcept;
  262. /** Indexes every bound codec block into schema rows sorted by handle. */
  263. [[nodiscard]] bool build_codec_index(const Image& image,
  264. std::vector<SchemaRow>& rows,
  265. std::vector<std::uint32_t>& fieldValues,
  266. const char*& error) noexcept;
  267. } // namespace sunrise::client::content::activity::sdk_generation::decode_plans::internal