Wasi.h 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. /*
  2. * Copyright (c) 2023, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/DistinctNumeric.h>
  8. #include <AK/Endian.h>
  9. #include <AK/Function.h>
  10. #include <AK/LexicalPath.h>
  11. #include <AK/RedBlackTree.h>
  12. #include <AK/String.h>
  13. #include <AK/Vector.h>
  14. #include <LibWasm/AbstractMachine/AbstractMachine.h>
  15. #include <LibWasm/Forward.h>
  16. namespace Wasm::Wasi::ABI {
  17. // NOTE: The "real" ABI used in the wild is described by [api.h from libc-bottom-half](https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h)
  18. // This is *not* the same ABI as the one described in the WASI spec, nor is it the same ABI as api.h on wasi-libc/master.
  19. // The highlights of the ABI are:
  20. // - (most) structs are passed as pointers to heap.
  21. // - arrays are fat pointers splat across two arguments
  22. // - return object locations are also passed as arguments, the number of arguments depends on the return type itself:
  23. // - ArgsSizes / EnvironSizes / the return type of sock_recv use two arguments
  24. // - everything else is passed like a normal struct
  25. template<auto impl>
  26. struct InvocationOf {
  27. HostFunction operator()(Implementation&, StringView name);
  28. };
  29. template<typename T, size_t N>
  30. void serialize(T const&, Array<Bytes, N>);
  31. template<typename T, size_t N>
  32. T deserialize(Array<ReadonlyBytes, N> const&);
  33. template<typename T>
  34. struct ToCompatibleValue {
  35. using Type = void;
  36. };
  37. template<typename T>
  38. struct CompatibleValue {
  39. typename ToCompatibleValue<T>::Type value;
  40. Wasm::Value to_wasm_value() const;
  41. };
  42. template<typename T>
  43. CompatibleValue<T> to_compatible_value(Wasm::Value const&);
  44. template<typename T>
  45. T deserialize(CompatibleValue<T> const&);
  46. }
  47. namespace Wasm::Wasi {
  48. // NOTE: This is a copy of LittleEndian from Endian.h,
  49. // we can't use those because they have a packed attribute, and depend on it;
  50. // but we want proper alignment on these types.
  51. template<typename T>
  52. class alignas(T) LittleEndian {
  53. public:
  54. constexpr LittleEndian() = default;
  55. constexpr LittleEndian(T value)
  56. : m_value(AK::convert_between_host_and_little_endian(value))
  57. {
  58. }
  59. constexpr operator T() const { return AK::convert_between_host_and_little_endian(m_value); }
  60. constexpr T value() const { return AK::convert_between_host_and_little_endian(m_value); }
  61. LittleEndian& operator+=(T other)
  62. {
  63. m_value = AK::convert_between_host_and_little_endian(AK::convert_between_host_and_little_endian(m_value) + other);
  64. return *this;
  65. }
  66. // This returns the internal representation. In this case, that is the value stored in little endian format.
  67. constexpr Bytes bytes() { return Bytes { &m_value, sizeof(m_value) }; }
  68. constexpr ReadonlyBytes bytes() const { return ReadonlyBytes { &m_value, sizeof(m_value) }; }
  69. void serialize_into(Array<Bytes, 1> bytes) const;
  70. static LittleEndian read_from(Array<ReadonlyBytes, 1> const& bytes);
  71. private:
  72. T m_value { 0 };
  73. };
  74. using Size = LittleEndian<u32>;
  75. using FileSize = LittleEndian<u64>;
  76. using Timestamp = LittleEndian<u64>;
  77. namespace Detail {
  78. template<typename>
  79. struct __Pointer_tag;
  80. template<typename>
  81. struct __ConstPointer_tag;
  82. }
  83. // NOTE: Might need to be updated if WASI ever supports memory64.
  84. using UnderlyingPointerType = u32;
  85. template<typename T>
  86. using Pointer = DistinctNumeric<LittleEndian<UnderlyingPointerType>, Detail::__Pointer_tag<T>, AK::DistinctNumericFeature::Comparison>;
  87. template<typename T>
  88. using ConstPointer = DistinctNumeric<LittleEndian<UnderlyingPointerType>, Detail::__ConstPointer_tag<T>, AK::DistinctNumericFeature::Comparison>;
  89. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L70
  90. enum class ClockID : u32 {
  91. Realtime,
  92. Monotonic,
  93. ProcessCPUTimeID,
  94. ThreadCPUTimeID,
  95. };
  96. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L105
  97. enum class Errno : u16 {
  98. Success,
  99. TooBig,
  100. Access,
  101. AddressInUse,
  102. AddressNotAvailable,
  103. AFNotSupported,
  104. Again,
  105. Already,
  106. BadF,
  107. BadMessage,
  108. Busy,
  109. Canceled,
  110. Child,
  111. ConnectionAborted,
  112. ConnectionRefused,
  113. ConnectionReset,
  114. Deadlock,
  115. DestinationAddressRequired,
  116. Domain,
  117. DQuot, // Reserved, Unused.
  118. Exist,
  119. Fault,
  120. FBig,
  121. HostUnreachable,
  122. IdentifierRemoved,
  123. IllegalSequence,
  124. InProgress,
  125. Interrupted,
  126. Invalid,
  127. IO,
  128. IsConnected,
  129. IsDirectory,
  130. Loop,
  131. MFile,
  132. MLink,
  133. MessageSize,
  134. MultiHop, // Reserved, Unused.
  135. NameTooLong,
  136. NetworkDown,
  137. NetworkReset,
  138. NetworkUnreachable,
  139. NFile,
  140. NoBufferSpace,
  141. NoDevice,
  142. NoEntry,
  143. NoExec,
  144. NoLock,
  145. NoLink,
  146. NoMemory,
  147. NoMessage,
  148. NoProtocolOption,
  149. NoSpace,
  150. NoSys,
  151. NotConnected,
  152. NotDirectory,
  153. NotEmpty,
  154. NotRecoverable,
  155. NotSocket,
  156. NotSupported,
  157. NoTTY,
  158. NXIO,
  159. Overflow,
  160. OwnerDead,
  161. Permission,
  162. Pipe,
  163. Protocol,
  164. ProtocolNotSupported,
  165. ProtocolType,
  166. Range,
  167. ReadOnlyFS,
  168. SPipe,
  169. SRCH,
  170. Stale,
  171. TimedOut,
  172. TextBusy,
  173. XDev,
  174. NotCapable,
  175. };
  176. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L498
  177. struct Rights {
  178. using CompatibleType = u64;
  179. struct Bits {
  180. bool fd_datasync : 1;
  181. bool fd_read : 1;
  182. bool fd_seek : 1;
  183. bool fd_fdstat_set_flags : 1;
  184. bool fd_sync : 1;
  185. bool fd_tell : 1;
  186. bool fd_write : 1;
  187. bool fd_advise : 1;
  188. bool fd_allocate : 1;
  189. bool path_create_directory : 1;
  190. bool path_create_file : 1;
  191. bool path_link_source : 1;
  192. bool path_link_target : 1;
  193. bool path_open : 1;
  194. bool fd_readdir : 1;
  195. bool path_readlink : 1;
  196. bool path_rename_source : 1;
  197. bool path_rename_target : 1;
  198. bool path_filestat_get : 1;
  199. bool path_filestat_set_size : 1;
  200. bool path_filestat_set_times : 1;
  201. bool fd_filestat_get : 1;
  202. bool fd_filestat_set_size : 1;
  203. bool fd_filestat_set_times : 1;
  204. bool path_symlink : 1;
  205. bool path_remove_directory : 1;
  206. bool path_unlink_file : 1;
  207. bool poll_fd_readwrite : 1;
  208. bool sock_shutdown : 1;
  209. bool sock_accept : 1;
  210. u8 _unused1 : 2;
  211. u32 _unused2 : 32;
  212. };
  213. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  214. union {
  215. Bits bits;
  216. LittleEndian<CompatibleType> data;
  217. };
  218. void serialize_into(Array<Bytes, 1> bytes) const;
  219. static Rights read_from(Array<ReadonlyBytes, 1> const& bytes);
  220. };
  221. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L663
  222. using FD = DistinctNumeric<LittleEndian<u32>, struct __FD_tag, AK::DistinctNumericFeature::Comparison>;
  223. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L671
  224. struct IOVec {
  225. Pointer<u8> buf;
  226. Size buf_len;
  227. static IOVec read_from(Array<ReadonlyBytes, 1> const& bytes);
  228. };
  229. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L692
  230. struct CIOVec {
  231. ConstPointer<u8> buf;
  232. Size buf_len;
  233. static CIOVec read_from(Array<ReadonlyBytes, 1> const& bytes);
  234. };
  235. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L713
  236. using FileDelta = LittleEndian<i64>;
  237. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L721
  238. enum class Whence : u8 {
  239. Set,
  240. Cur,
  241. End,
  242. };
  243. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L746
  244. using DirCookie = LittleEndian<u64>;
  245. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L754
  246. using DirNameLen = LittleEndian<u32>;
  247. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L762
  248. using INode = LittleEndian<u64>;
  249. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L770
  250. enum class FileType : u8 {
  251. Unknown,
  252. BlockDevice,
  253. CharacterDevice,
  254. Directory,
  255. RegularFile,
  256. SocketDGram,
  257. SocketStream,
  258. SymbolicLink,
  259. };
  260. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L818
  261. struct DirEnt {
  262. DirCookie d_next;
  263. INode d_ino;
  264. DirNameLen d_namlen;
  265. FileType d_type;
  266. u8 _padding[3] { 0 }; // Not part of the API, but the struct is required to be 24 bytes - even though it has no explicit padding.
  267. };
  268. static_assert(sizeof(DirEnt) == 24);
  269. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L851
  270. enum class Advice : u8 {
  271. Normal,
  272. Sequential,
  273. Random,
  274. WillNeed,
  275. DontNeed,
  276. NoReuse,
  277. };
  278. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L889
  279. struct FDFlags {
  280. using CompatibleType = u16;
  281. struct Bits {
  282. bool append : 1;
  283. bool dsync : 1;
  284. bool nonblock : 1;
  285. bool rsync : 1;
  286. bool sync : 1;
  287. u8 _unused1 : 3;
  288. u8 _unused2 : 8;
  289. };
  290. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  291. union {
  292. Bits bits;
  293. LittleEndian<CompatibleType> data;
  294. };
  295. void serialize_into(Array<Bytes, 1> bytes) const;
  296. static FDFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  297. };
  298. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L924
  299. struct FDStat {
  300. FileType fs_filetype;
  301. u8 _padding1 { 0 }; // Not part of the API.
  302. FDFlags fs_flags;
  303. u8 _padding2[4] { 0 }; // Not part of the API.
  304. Rights fs_rights_base;
  305. Rights fs_rights_inheriting;
  306. void serialize_into(Array<Bytes, 1> bytes) const;
  307. };
  308. static_assert(sizeof(FDStat) == 24);
  309. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L959
  310. using Device = LittleEndian<u64>;
  311. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L967
  312. struct FSTFlags {
  313. using CompatibleType = u16;
  314. struct Bits {
  315. bool atim : 1;
  316. bool atim_now : 1;
  317. bool mtim : 1;
  318. bool mtim_now : 1;
  319. u8 _unused1 : 4;
  320. u8 _unused2 : 8;
  321. };
  322. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  323. union {
  324. Bits bits;
  325. LittleEndian<CompatibleType> data;
  326. };
  327. void serialize_into(Array<Bytes, 1> bytes) const;
  328. static FSTFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  329. };
  330. static_assert(sizeof(FSTFlags) == 2);
  331. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L995
  332. struct LookupFlags {
  333. using CompatibleType = u32;
  334. struct Bits {
  335. bool symlink_follow : 1;
  336. u8 _unused1 : 7;
  337. u8 _unused2 : 8;
  338. u16 _unused3 : 16;
  339. };
  340. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  341. union {
  342. Bits bits;
  343. LittleEndian<CompatibleType> data;
  344. };
  345. void serialize_into(Array<Bytes, 1> bytes) const;
  346. static LookupFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  347. };
  348. static_assert(sizeof(LookupFlags) == 4);
  349. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1008
  350. struct OFlags {
  351. using CompatibleType = u16;
  352. struct Bits {
  353. bool creat : 1;
  354. bool directory : 1;
  355. bool excl : 1;
  356. bool trunc : 1;
  357. u8 _unused1 : 4;
  358. u8 _unused2 : 8;
  359. };
  360. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  361. union {
  362. Bits bits;
  363. LittleEndian<CompatibleType> data;
  364. };
  365. static OFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  366. };
  367. static_assert(sizeof(OFlags) == 2);
  368. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1036
  369. using LinkCount = LittleEndian<u64>;
  370. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1044
  371. struct FileStat {
  372. Device dev;
  373. INode ino;
  374. FileType filetype;
  375. u8 _padding1[7] { 0 }; // Not part of the API.
  376. LinkCount nlink;
  377. FileSize size;
  378. Timestamp atim;
  379. Timestamp mtim;
  380. Timestamp ctim;
  381. void serialize_into(Array<Bytes, 1> bytes) const;
  382. };
  383. static_assert(sizeof(FileStat) == 64);
  384. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1102
  385. using UserData = LittleEndian<u64>;
  386. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1110
  387. enum class EventType : u8 {
  388. Clock,
  389. FDRead,
  390. FDWrite,
  391. };
  392. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1137
  393. struct EventRWFlags {
  394. using CompatibleType = u16;
  395. struct Bits {
  396. bool fd_readwrite_hangup : 1;
  397. u8 _unused1 : 7;
  398. u8 _unused2 : 8;
  399. };
  400. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  401. union {
  402. Bits bits;
  403. LittleEndian<CompatibleType> data;
  404. };
  405. void serialize_into(Array<Bytes, 1> bytes) const;
  406. static EventRWFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  407. };
  408. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1151
  409. struct EventFDReadWrite {
  410. FileSize nbytes;
  411. u8 _padding[4] { 0 }; // Not part of the API.
  412. EventRWFlags flags;
  413. void serialize_into(Array<Bytes, 1> bytes) const;
  414. static EventFDReadWrite read_from(Array<ReadonlyBytes, 1> const& bytes);
  415. };
  416. static_assert(sizeof(EventFDReadWrite) == 16);
  417. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1186
  418. struct Event {
  419. UserData userdata;
  420. Errno errno_;
  421. EventType type;
  422. u8 _padding[5] { 0 }; // Not part of the API.
  423. EventFDReadWrite fd_readwrite;
  424. void serialize_into(Array<Bytes, 1> bytes) const;
  425. static Event read_from(Array<ReadonlyBytes, 1> const& bytes);
  426. };
  427. static_assert(sizeof(Event) == 32);
  428. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1220
  429. struct SubClockFlags {
  430. using CompatibleType = u16;
  431. struct Bits {
  432. bool subscription_clock_abstime : 1;
  433. u8 _unused1 : 7;
  434. u8 _unused2 : 8;
  435. };
  436. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  437. union {
  438. Bits bits;
  439. LittleEndian<CompatibleType> data;
  440. };
  441. void serialize_into(Array<Bytes, 1> bytes) const;
  442. static SubClockFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  443. };
  444. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1237
  445. struct SubscriptionClock {
  446. ClockID id;
  447. u8 _padding1[4] { 0 }; // Not part of the API.
  448. Timestamp timeout;
  449. Timestamp precision;
  450. SubClockFlags flags;
  451. u8 _padding2[4] { 0 }; // Not part of the API.
  452. void serialize_into(Array<Bytes, 1> bytes) const;
  453. static SubscriptionClock read_from(Array<ReadonlyBytes, 1> const& bytes);
  454. };
  455. static_assert(sizeof(SubscriptionClock) == 32);
  456. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1272
  457. struct SubscriptionFDReadWrite {
  458. FD file_descriptor;
  459. void serialize_into(Array<Bytes, 1> bytes) const;
  460. static SubscriptionFDReadWrite read_from(Array<ReadonlyBytes, 1> const& bytes);
  461. };
  462. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1287
  463. union SubscriptionU {
  464. SubscriptionClock clock;
  465. SubscriptionFDReadWrite fd_read;
  466. SubscriptionFDReadWrite fd_write;
  467. };
  468. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1306
  469. struct Subscription {
  470. UserData userdata;
  471. EventType type;
  472. u8 _padding[7] { 0 }; // Not part of the API.
  473. SubscriptionU u;
  474. void serialize_into(Array<Bytes, 1> bytes) const;
  475. static Subscription read_from(Array<ReadonlyBytes, 1> const& bytes);
  476. };
  477. static_assert(sizeof(Subscription) == 48);
  478. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1334
  479. using ExitCode = LittleEndian<u32>;
  480. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1342
  481. enum class Signal : u8 {
  482. None,
  483. HUP,
  484. INT,
  485. QUIT,
  486. ILL,
  487. TRAP,
  488. ABRT,
  489. BUS,
  490. FPE,
  491. KILL,
  492. USR1,
  493. SEGV,
  494. USR2,
  495. PIPE,
  496. ALRM,
  497. TERM,
  498. CHLD,
  499. CONT,
  500. STOP,
  501. TSTP,
  502. TTIN,
  503. TTOU,
  504. URG,
  505. XCPU,
  506. XFSZ,
  507. VTALRM,
  508. PROF,
  509. WINCH,
  510. POLL,
  511. PWR,
  512. SYS,
  513. };
  514. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1536
  515. struct RIFlags {
  516. using CompatibleType = u16;
  517. struct Bits {
  518. bool recv_peek : 1;
  519. bool recv_waitall : 1;
  520. u8 _unused1 : 6;
  521. u8 _unused2 : 8;
  522. };
  523. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  524. union {
  525. Bits bits;
  526. LittleEndian<CompatibleType> data;
  527. };
  528. static RIFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  529. };
  530. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1554
  531. struct ROFlags {
  532. using CompatibleType = u16;
  533. struct Bits {
  534. bool recv_data_truncated : 1;
  535. u8 _unused1 : 7;
  536. u8 _unused2 : 8;
  537. };
  538. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  539. union {
  540. Bits bits;
  541. LittleEndian<CompatibleType> data;
  542. };
  543. void serialize_into(Array<Bytes, 1> bytes) const;
  544. };
  545. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1568
  546. using SIFlags = LittleEndian<u16>;
  547. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1576
  548. struct SDFlags {
  549. using CompatibleType = u8;
  550. struct Bits {
  551. bool rd : 1;
  552. bool wr : 1;
  553. u8 _unused : 6;
  554. };
  555. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  556. union {
  557. Bits bits;
  558. LittleEndian<CompatibleType> data;
  559. };
  560. void serialize_into(Array<Bytes, 1> bytes) const;
  561. static SDFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  562. };
  563. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1594
  564. enum class PreOpenType : u8 {
  565. Dir,
  566. };
  567. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1607
  568. struct PreStatDir {
  569. Size pr_name_len;
  570. void serialize_into(Array<Bytes, 1> bytes) const;
  571. static PreStatDir read_from(Array<ReadonlyBytes, 1> const& bytes);
  572. };
  573. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1636
  574. struct PreStat {
  575. PreOpenType type;
  576. u8 _padding[3] { 0 }; // Not part of the API.
  577. union {
  578. PreStatDir dir;
  579. };
  580. void serialize_into(Array<Bytes, 1> bytes) const;
  581. };
  582. static_assert(sizeof(PreStat) == 8);
  583. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1676
  584. struct ArgsSizes {
  585. Size count;
  586. Size size;
  587. using SerializationComponents = TypeList<Size, Size>;
  588. void serialize_into(Array<Bytes, 2> bytes) const;
  589. };
  590. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1708
  591. struct EnvironSizes {
  592. Size count;
  593. Size size;
  594. using SerializationComponents = TypeList<Size, Size>;
  595. void serialize_into(Array<Bytes, 2> bytes) const;
  596. };
  597. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L2664
  598. struct SockRecvResult {
  599. Size size;
  600. ROFlags roflags;
  601. u8 _padding[2] { 0 }; // Not part of the API.
  602. using SerializationComponents = TypeList<Size, ROFlags>;
  603. void serialize_into(Array<Bytes, 2> bytes) const;
  604. };
  605. static_assert(sizeof(SockRecvResult) == 8);
  606. template<typename TResult, typename Tag = u32>
  607. struct Result {
  608. Result(TResult&& result)
  609. : bits {}
  610. , tag(0)
  611. {
  612. new (&bits) TResult(move(result));
  613. }
  614. Result(Errno&& error)
  615. : bits {}
  616. , tag(1)
  617. {
  618. new (&bits) Errno(error);
  619. }
  620. Optional<TResult&> result() const
  621. {
  622. if (tag == 0)
  623. return *bit_cast<TResult*>(&bits[0]);
  624. return {};
  625. }
  626. Optional<Errno&> error() const
  627. {
  628. if (tag == 1)
  629. return *bit_cast<Errno*>(&bits[0]);
  630. return {};
  631. }
  632. bool is_error() const { return tag == 1; }
  633. template<size_t N>
  634. Errno serialize_into(Array<Bytes, N>&& spans) const
  635. {
  636. if (tag == 1)
  637. return error().value();
  638. ABI::serialize(*result(), move(spans));
  639. return Errno::Success;
  640. }
  641. private:
  642. alignas(max(alignof(TResult), alignof(Errno))) u8 bits[max(sizeof(TResult), sizeof(Errno))];
  643. LittleEndian<Tag> tag;
  644. };
  645. template<typename Tag>
  646. struct Result<void, Tag> {
  647. Result()
  648. : error_bits {}
  649. , tag(0)
  650. {
  651. }
  652. Result(Errno&& error)
  653. : error_bits {}
  654. , tag(1)
  655. {
  656. new (&error_bits) Errno(error);
  657. }
  658. Optional<Empty> result() const
  659. {
  660. if (tag == 0)
  661. return { Empty {} };
  662. return {};
  663. }
  664. Optional<Errno&> error() const
  665. {
  666. if (tag == 1)
  667. return *bit_cast<Errno*>(&error_bits[0]);
  668. return {};
  669. }
  670. bool is_error() const { return tag == 1; }
  671. private:
  672. alignas(Errno) u8 error_bits[sizeof(Errno)];
  673. LittleEndian<Tag> tag;
  674. };
  675. struct Implementation {
  676. struct MappedPath {
  677. LexicalPath host_path;
  678. LexicalPath mapped_path;
  679. mutable Optional<int> opened_fd {};
  680. };
  681. struct Details {
  682. Function<Vector<AK::String>()> provide_arguments;
  683. Function<Vector<AK::String>()> provide_environment;
  684. Function<Vector<MappedPath>()> provide_preopened_directories;
  685. };
  686. explicit Implementation(Details&& details)
  687. : provide_arguments(move(details.provide_arguments))
  688. , provide_environment(move(details.provide_environment))
  689. , provide_preopened_directories(move(details.provide_preopened_directories))
  690. {
  691. // Map all of std{in,out,err} by default.
  692. m_fd_map.insert(0, 0);
  693. m_fd_map.insert(1, 1);
  694. m_fd_map.insert(2, 2);
  695. }
  696. ErrorOr<HostFunction> function_by_name(StringView);
  697. private:
  698. template<auto impl>
  699. HostFunction invocation_of(StringView name) { return ABI::InvocationOf<impl> {}(*this, name); }
  700. ErrorOr<Result<void>> impl$args_get(Configuration&, Pointer<Pointer<u8>> argv, Pointer<u8> argv_buf);
  701. ErrorOr<Result<ArgsSizes>> impl$args_sizes_get(Configuration&);
  702. ErrorOr<Result<void>> impl$environ_get(Configuration&, Pointer<Pointer<u8>> environ, Pointer<u8> environ_buf);
  703. ErrorOr<Result<EnvironSizes>> impl$environ_sizes_get(Configuration&);
  704. ErrorOr<Result<Timestamp>> impl$clock_res_get(Configuration&, ClockID id);
  705. ErrorOr<Result<Timestamp>> impl$clock_time_get(Configuration&, ClockID id, Timestamp precision);
  706. ErrorOr<Result<void>> impl$fd_advise(Configuration&, FD, FileSize offset, FileSize len, Advice);
  707. ErrorOr<Result<void>> impl$fd_allocate(Configuration&, FD, FileSize offset, FileSize len);
  708. ErrorOr<Result<void>> impl$fd_close(Configuration&, FD);
  709. ErrorOr<Result<void>> impl$fd_datasync(Configuration&, FD);
  710. ErrorOr<Result<FDStat>> impl$fd_fdstat_get(Configuration&, FD);
  711. ErrorOr<Result<void>> impl$fd_fdstat_set_flags(Configuration&, FD, FDFlags);
  712. ErrorOr<Result<void>> impl$fd_fdstat_set_rights(Configuration&, FD, Rights fs_rights_base, Rights fs_rights_inheriting);
  713. ErrorOr<Result<FileStat>> impl$fd_filestat_get(Configuration&, FD);
  714. ErrorOr<Result<void>> impl$fd_filestat_set_size(Configuration&, FD, FileSize);
  715. ErrorOr<Result<void>> impl$fd_filestat_set_times(Configuration&, FD, Timestamp atim, Timestamp mtim, FSTFlags);
  716. ErrorOr<Result<Size>> impl$fd_pread(Configuration&, FD, Pointer<IOVec> iovs, Size iovs_len, FileSize offset);
  717. ErrorOr<Result<PreStat>> impl$fd_prestat_get(Configuration&, FD);
  718. ErrorOr<Result<void>> impl$fd_prestat_dir_name(Configuration&, FD, Pointer<u8> path, Size path_len);
  719. ErrorOr<Result<Size>> impl$fd_pwrite(Configuration&, FD, Pointer<CIOVec> iovs, Size iovs_len, FileSize offset);
  720. ErrorOr<Result<Size>> impl$fd_read(Configuration&, FD, Pointer<IOVec> iovs, Size iovs_len);
  721. ErrorOr<Result<Size>> impl$fd_readdir(Configuration&, FD, Pointer<u8> buf, Size buf_len, DirCookie cookie);
  722. ErrorOr<Result<void>> impl$fd_renumber(Configuration&, FD from, FD to);
  723. ErrorOr<Result<FileSize>> impl$fd_seek(Configuration&, FD, FileDelta offset, Whence whence);
  724. ErrorOr<Result<void>> impl$fd_sync(Configuration&, FD);
  725. ErrorOr<Result<FileSize>> impl$fd_tell(Configuration&, FD);
  726. ErrorOr<Result<Size>> impl$fd_write(Configuration&, FD, Pointer<CIOVec> iovs, Size iovs_len);
  727. ErrorOr<Result<void>> impl$path_create_directory(Configuration&, FD, Pointer<u8> path, Size path_len);
  728. ErrorOr<Result<FileStat>> impl$path_filestat_get(Configuration&, FD, LookupFlags, ConstPointer<u8> path, Size path_len);
  729. ErrorOr<Result<void>> impl$path_filestat_set_times(Configuration&, FD, LookupFlags, Pointer<u8> path, Size path_len, Timestamp atim, Timestamp mtim, FSTFlags);
  730. ErrorOr<Result<void>> impl$path_link(Configuration&, FD, LookupFlags, Pointer<u8> old_path, Size old_path_len, FD, Pointer<u8> new_path, Size new_path_len);
  731. ErrorOr<Result<FD>> impl$path_open(Configuration&, FD, LookupFlags, Pointer<u8> path, Size path_len, OFlags, Rights fs_rights_base, Rights fs_rights_inheriting, FDFlags fd_flags);
  732. ErrorOr<Result<Size>> impl$path_readlink(Configuration&, FD, LookupFlags, Pointer<u8> path, Size path_len, Pointer<u8> buf, Size buf_len);
  733. ErrorOr<Result<void>> impl$path_remove_directory(Configuration&, FD, Pointer<u8> path, Size path_len);
  734. ErrorOr<Result<void>> impl$path_rename(Configuration&, FD, Pointer<u8> old_path, Size old_path_len, FD, Pointer<u8> new_path, Size new_path_len);
  735. ErrorOr<Result<void>> impl$path_symlink(Configuration&, Pointer<u8> old_path, Size old_path_len, FD, Pointer<u8> new_path, Size new_path_len);
  736. ErrorOr<Result<void>> impl$path_unlink_file(Configuration&, FD, Pointer<u8> path, Size path_len);
  737. ErrorOr<Result<Size>> impl$poll_oneoff(Configuration&, ConstPointer<Subscription> in, Pointer<Event> out, Size nsubscriptions);
  738. ErrorOr<Result<void>> impl$proc_exit(Configuration&, ExitCode); // Note: noreturn.
  739. ErrorOr<Result<void>> impl$proc_raise(Configuration&, Signal);
  740. ErrorOr<Result<void>> impl$sched_yield(Configuration&);
  741. ErrorOr<Result<void>> impl$random_get(Configuration&, Pointer<u8> buf, Size buf_len);
  742. ErrorOr<Result<FD>> impl$sock_accept(Configuration&, FD fd, FDFlags fd_flags);
  743. ErrorOr<Result<SockRecvResult>> impl$sock_recv(Configuration&, FD fd, Pointer<IOVec> ri_data, Size ri_data_len, RIFlags ri_flags);
  744. ErrorOr<Result<Size>> impl$sock_send(Configuration&, FD fd, Pointer<CIOVec> si_data, Size ri_data_len, SIFlags si_flags);
  745. ErrorOr<Result<void>> impl$sock_shutdown(Configuration&, FD fd, SDFlags how);
  746. Vector<AK::String> const& arguments() const;
  747. Vector<AK::String> const& environment() const;
  748. Vector<MappedPath> const& preopened_directories() const;
  749. using PreopenedDirectoryDescriptor = DistinctNumeric<LittleEndian<size_t>, struct PreopenedDirectoryDescriptor_tag, AK::DistinctNumericFeature::Comparison, AK::DistinctNumericFeature::CastToUnderlying, AK::DistinctNumericFeature::Increment>;
  750. using UnmappedDescriptor = DistinctNumeric<LittleEndian<size_t>, struct UnmappedDescriptor_tag, AK::DistinctNumericFeature::Comparison, AK::DistinctNumericFeature::CastToUnderlying>;
  751. using MappedDescriptor = Variant<u32, PreopenedDirectoryDescriptor>;
  752. using Descriptor = Variant<u32, PreopenedDirectoryDescriptor, UnmappedDescriptor>;
  753. Descriptor map_fd(FD);
  754. public:
  755. Function<Vector<AK::String>()> provide_arguments;
  756. Function<Vector<AK::String>()> provide_environment;
  757. Function<Vector<MappedPath>()> provide_preopened_directories;
  758. private:
  759. struct Cache {
  760. Optional<Vector<AK::String>> cached_arguments;
  761. Optional<Vector<AK::String>> cached_environment;
  762. Optional<Vector<MappedPath>> cached_preopened_directories;
  763. };
  764. mutable Cache cache {};
  765. RedBlackTree<u32, MappedDescriptor> m_fd_map;
  766. size_t m_first_unmapped_preopened_directory_index { 0 };
  767. };
  768. #undef IMPL
  769. }
  770. namespace Wasm::Wasi::ABI {
  771. template<typename T, typename... Args>
  772. struct ToCompatibleValue<DistinctNumeric<T, Args...>> {
  773. using Type = typename ToCompatibleValue<T>::Type;
  774. };
  775. template<typename T>
  776. struct ToCompatibleValue<LittleEndian<T>> {
  777. using Type = MakeSigned<T>;
  778. };
  779. template<typename T>
  780. requires(requires { declval<typename T::CompatibleType>(); })
  781. struct ToCompatibleValue<T> {
  782. using Type = MakeSigned<typename T::CompatibleType>;
  783. };
  784. template<Integral T>
  785. struct ToCompatibleValue<T> {
  786. using Type = MakeSigned<T>;
  787. };
  788. template<Enum T>
  789. struct ToCompatibleValue<T> {
  790. using Type = MakeSigned<UnderlyingType<T>>;
  791. };
  792. }
  793. template<typename T>
  794. struct AK::Formatter<Wasm::Wasi::LittleEndian<T>> : AK::Formatter<T> {
  795. ErrorOr<void> format(FormatBuilder& builder, Wasm::Wasi::LittleEndian<T> value)
  796. {
  797. return Formatter<T>::format(builder, value.operator T());
  798. }
  799. };