Wasi.h 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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. u64 _unused : 34;
  211. };
  212. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  213. union {
  214. Bits bits;
  215. LittleEndian<CompatibleType> data;
  216. };
  217. void serialize_into(Array<Bytes, 1> bytes) const;
  218. static Rights read_from(Array<ReadonlyBytes, 1> const& bytes);
  219. };
  220. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L663
  221. using FD = DistinctNumeric<LittleEndian<u32>, struct __FD_tag, AK::DistinctNumericFeature::Comparison>;
  222. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L671
  223. struct IOVec {
  224. Pointer<u8> buf;
  225. Size buf_len;
  226. static IOVec read_from(Array<ReadonlyBytes, 1> const& bytes);
  227. };
  228. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L692
  229. struct CIOVec {
  230. ConstPointer<u8> buf;
  231. Size buf_len;
  232. static CIOVec read_from(Array<ReadonlyBytes, 1> const& bytes);
  233. };
  234. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L713
  235. using FileDelta = LittleEndian<i64>;
  236. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L721
  237. enum class Whence : u8 {
  238. Set,
  239. Cur,
  240. End,
  241. };
  242. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L746
  243. using DirCookie = LittleEndian<u64>;
  244. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L754
  245. using DirNameLen = LittleEndian<u32>;
  246. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L762
  247. using INode = LittleEndian<u64>;
  248. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L770
  249. enum class FileType : u8 {
  250. Unknown,
  251. BlockDevice,
  252. CharacterDevice,
  253. Directory,
  254. RegularFile,
  255. SocketDGram,
  256. SocketStream,
  257. SymbolicLink,
  258. };
  259. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L818
  260. struct DirEnt {
  261. DirCookie d_next;
  262. INode d_ino;
  263. DirNameLen d_namlen;
  264. FileType d_type;
  265. 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.
  266. };
  267. static_assert(sizeof(DirEnt) == 24);
  268. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L851
  269. enum class Advice : u8 {
  270. Normal,
  271. Sequential,
  272. Random,
  273. WillNeed,
  274. DontNeed,
  275. NoReuse,
  276. };
  277. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L889
  278. struct FDFlags {
  279. using CompatibleType = u16;
  280. struct Bits {
  281. bool append : 1;
  282. bool dsync : 1;
  283. bool nonblock : 1;
  284. bool rsync : 1;
  285. bool sync : 1;
  286. u16 _unused : 11;
  287. };
  288. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  289. union {
  290. Bits bits;
  291. LittleEndian<CompatibleType> data;
  292. };
  293. void serialize_into(Array<Bytes, 1> bytes) const;
  294. static FDFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  295. };
  296. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L924
  297. struct FDStat {
  298. FileType fs_filetype;
  299. FDFlags fs_flags;
  300. Rights fs_rights_base;
  301. Rights fs_rights_inheriting;
  302. void serialize_into(Array<Bytes, 1> bytes) const;
  303. };
  304. static_assert(sizeof(FDStat) == 24);
  305. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L959
  306. using Device = LittleEndian<u64>;
  307. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L967
  308. struct FSTFlags {
  309. using CompatibleType = u16;
  310. struct Bits {
  311. bool atim : 1;
  312. bool atim_now : 1;
  313. bool mtim : 1;
  314. bool mtim_now : 1;
  315. u16 _unused : 12;
  316. };
  317. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  318. union {
  319. Bits bits;
  320. LittleEndian<CompatibleType> data;
  321. };
  322. void serialize_into(Array<Bytes, 1> bytes) const;
  323. static FSTFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  324. };
  325. static_assert(sizeof(FSTFlags) == 2);
  326. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L995
  327. struct LookupFlags {
  328. using CompatibleType = u32;
  329. struct Bits {
  330. bool symlink_follow : 1;
  331. u32 _unused : 31;
  332. };
  333. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  334. union {
  335. Bits bits;
  336. LittleEndian<CompatibleType> data;
  337. };
  338. void serialize_into(Array<Bytes, 1> bytes) const;
  339. static LookupFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  340. };
  341. static_assert(sizeof(LookupFlags) == 4);
  342. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1008
  343. struct OFlags {
  344. using CompatibleType = u16;
  345. struct Bits {
  346. bool creat : 1;
  347. bool directory : 1;
  348. bool excl : 1;
  349. bool trunc : 1;
  350. u16 _unused : 12;
  351. };
  352. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  353. union {
  354. Bits bits;
  355. LittleEndian<CompatibleType> data;
  356. };
  357. static OFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  358. };
  359. static_assert(sizeof(OFlags) == 2);
  360. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1036
  361. using LinkCount = LittleEndian<u64>;
  362. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1044
  363. struct FileStat {
  364. Device dev;
  365. INode ino;
  366. FileType filetype;
  367. LinkCount nlink;
  368. FileSize size;
  369. Timestamp atim;
  370. Timestamp mtim;
  371. Timestamp ctim;
  372. void serialize_into(Array<Bytes, 1> bytes) const;
  373. };
  374. static_assert(sizeof(FileStat) == 64);
  375. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1102
  376. using UserData = LittleEndian<u64>;
  377. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1110
  378. enum class EventType : u8 {
  379. Clock,
  380. FDRead,
  381. FDWrite,
  382. };
  383. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1137
  384. struct EventRWFlags {
  385. using CompatibleType = u16;
  386. struct Bits {
  387. bool fd_readwrite_hangup : 1;
  388. u16 _unused : 15;
  389. };
  390. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  391. union {
  392. Bits bits;
  393. LittleEndian<CompatibleType> data;
  394. };
  395. void serialize_into(Array<Bytes, 1> bytes) const;
  396. static EventRWFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  397. };
  398. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1151
  399. struct EventFDReadWrite {
  400. FileSize nbytes;
  401. EventRWFlags flags;
  402. void serialize_into(Array<Bytes, 1> bytes) const;
  403. static EventFDReadWrite read_from(Array<ReadonlyBytes, 1> const& bytes);
  404. };
  405. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1186
  406. struct Event {
  407. UserData userdata;
  408. Errno errno_;
  409. EventType type;
  410. EventFDReadWrite fd_readwrite;
  411. void serialize_into(Array<Bytes, 1> bytes) const;
  412. static Event read_from(Array<ReadonlyBytes, 1> const& bytes);
  413. };
  414. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1220
  415. struct SubClockFlags {
  416. using CompatibleType = u16;
  417. struct Bits {
  418. bool subscription_clock_abstime : 1;
  419. u16 _unused : 15;
  420. };
  421. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  422. union {
  423. Bits bits;
  424. LittleEndian<CompatibleType> data;
  425. };
  426. void serialize_into(Array<Bytes, 1> bytes) const;
  427. static SubClockFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  428. };
  429. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1237
  430. struct SubscriptionClock {
  431. ClockID id;
  432. Timestamp timeout;
  433. Timestamp precision;
  434. SubClockFlags flags;
  435. void serialize_into(Array<Bytes, 1> bytes) const;
  436. static SubscriptionClock read_from(Array<ReadonlyBytes, 1> const& bytes);
  437. };
  438. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1272
  439. struct SubscriptionFDReadWrite {
  440. FD file_descriptor;
  441. void serialize_into(Array<Bytes, 1> bytes) const;
  442. static SubscriptionFDReadWrite 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#L1287
  445. struct SubscriptionU {
  446. u8 tag;
  447. union {
  448. SubscriptionClock clock;
  449. SubscriptionFDReadWrite fd_read;
  450. SubscriptionFDReadWrite fd_write;
  451. };
  452. void serialize_into(Array<Bytes, 1> bytes) const;
  453. static SubscriptionU read_from(Array<ReadonlyBytes, 1> const& bytes);
  454. };
  455. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1306
  456. struct Subscription {
  457. UserData userdata;
  458. SubscriptionU u;
  459. void serialize_into(Array<Bytes, 1> bytes) const;
  460. static Subscription read_from(Array<ReadonlyBytes, 1> const& bytes);
  461. };
  462. static_assert(sizeof(Subscription) == 48);
  463. static_assert(alignof(Subscription) == 8);
  464. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1334
  465. using ExitCode = LittleEndian<u32>;
  466. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1342
  467. enum class Signal : u8 {
  468. None,
  469. HUP,
  470. INT,
  471. QUIT,
  472. ILL,
  473. TRAP,
  474. ABRT,
  475. BUS,
  476. FPE,
  477. KILL,
  478. USR1,
  479. SEGV,
  480. USR2,
  481. PIPE,
  482. ALRM,
  483. TERM,
  484. CHLD,
  485. CONT,
  486. STOP,
  487. TSTP,
  488. TTIN,
  489. TTOU,
  490. URG,
  491. XCPU,
  492. XFSZ,
  493. VTALRM,
  494. PROF,
  495. WINCH,
  496. POLL,
  497. PWR,
  498. SYS,
  499. };
  500. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1536
  501. struct RIFlags {
  502. using CompatibleType = u16;
  503. struct Bits {
  504. bool recv_peek : 1;
  505. bool recv_waitall : 1;
  506. u16 _unused : 14;
  507. };
  508. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  509. union {
  510. Bits bits;
  511. LittleEndian<CompatibleType> data;
  512. };
  513. static RIFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  514. };
  515. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1554
  516. struct ROFlags {
  517. using CompatibleType = u16;
  518. struct Bits {
  519. bool recv_data_truncated : 1;
  520. u16 _unused : 15;
  521. };
  522. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  523. union {
  524. Bits bits;
  525. LittleEndian<CompatibleType> data;
  526. };
  527. void serialize_into(Array<Bytes, 1> bytes) const;
  528. };
  529. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1568
  530. using SIFlags = LittleEndian<u16>;
  531. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1576
  532. struct SDFlags {
  533. using CompatibleType = u8;
  534. struct Bits {
  535. bool rd : 1;
  536. bool wr : 1;
  537. u8 _unused : 6;
  538. };
  539. static_assert(sizeof(Bits) == sizeof(CompatibleType));
  540. union {
  541. Bits bits;
  542. LittleEndian<CompatibleType> data;
  543. };
  544. void serialize_into(Array<Bytes, 1> bytes) const;
  545. static SDFlags read_from(Array<ReadonlyBytes, 1> const& bytes);
  546. };
  547. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1594
  548. enum class PreOpenType : u8 {
  549. Dir,
  550. };
  551. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1607
  552. struct PreStatDir {
  553. Size pr_name_len;
  554. void serialize_into(Array<Bytes, 1> bytes) const;
  555. static PreStatDir read_from(Array<ReadonlyBytes, 1> const& bytes);
  556. };
  557. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1636
  558. struct PreStat {
  559. u8 tag;
  560. union {
  561. PreStatDir dir;
  562. };
  563. void serialize_into(Array<Bytes, 1> bytes) const;
  564. };
  565. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1676
  566. struct ArgsSizes {
  567. Size count;
  568. Size size;
  569. using SerializationComponents = TypeList<Size, Size>;
  570. void serialize_into(Array<Bytes, 2> bytes) const;
  571. };
  572. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L1708
  573. struct EnvironSizes {
  574. Size count;
  575. Size size;
  576. using SerializationComponents = TypeList<Size, Size>;
  577. void serialize_into(Array<Bytes, 2> bytes) const;
  578. };
  579. // https://github.com/WebAssembly/wasi-libc/blob/2c2fc9a2fddd0927a66f1c142e65c8dab6f5c5d7/libc-bottom-half/headers/public/wasi/api.h#L2664
  580. struct SockRecvResult {
  581. Size size;
  582. ROFlags roflags;
  583. using SerializationComponents = TypeList<Size, ROFlags>;
  584. void serialize_into(Array<Bytes, 2> bytes) const;
  585. };
  586. template<typename TResult, typename Tag = u32>
  587. struct Result {
  588. Result(TResult&& result)
  589. : bits {}
  590. , tag(0)
  591. {
  592. new (&bits) TResult(move(result));
  593. }
  594. Result(Errno&& error)
  595. : bits {}
  596. , tag(1)
  597. {
  598. new (&bits) Errno(error);
  599. }
  600. Optional<TResult&> result() const
  601. {
  602. if (tag == 0)
  603. return *bit_cast<TResult*>(&bits[0]);
  604. return {};
  605. }
  606. Optional<Errno&> error() const
  607. {
  608. if (tag == 1)
  609. return *bit_cast<Errno*>(&bits[0]);
  610. return {};
  611. }
  612. bool is_error() const { return tag == 1; }
  613. template<size_t N>
  614. Errno serialize_into(Array<Bytes, N>&& spans) const
  615. {
  616. if (tag == 1)
  617. return error().value();
  618. ABI::serialize(*result(), move(spans));
  619. return Errno::Success;
  620. }
  621. private:
  622. alignas(max(alignof(TResult), alignof(Errno))) u8 bits[max(sizeof(TResult), sizeof(Errno))];
  623. LittleEndian<Tag> tag;
  624. };
  625. template<typename Tag>
  626. struct Result<void, Tag> {
  627. Result()
  628. : error_bits {}
  629. , tag(0)
  630. {
  631. }
  632. Result(Errno&& error)
  633. : error_bits {}
  634. , tag(1)
  635. {
  636. new (&error_bits) Errno(error);
  637. }
  638. Optional<Empty> result() const
  639. {
  640. if (tag == 0)
  641. return { Empty {} };
  642. return {};
  643. }
  644. Optional<Errno&> error() const
  645. {
  646. if (tag == 1)
  647. return *bit_cast<Errno*>(&error_bits[0]);
  648. return {};
  649. }
  650. bool is_error() const { return tag == 1; }
  651. private:
  652. alignas(Errno) u8 error_bits[sizeof(Errno)];
  653. LittleEndian<Tag> tag;
  654. };
  655. struct Implementation {
  656. struct MappedPath {
  657. LexicalPath host_path;
  658. LexicalPath mapped_path;
  659. mutable Optional<int> opened_fd {};
  660. };
  661. struct Details {
  662. Function<Vector<AK::String>()> provide_arguments;
  663. Function<Vector<AK::String>()> provide_environment;
  664. Function<Vector<MappedPath>()> provide_preopened_directories;
  665. };
  666. explicit Implementation(Details&& details)
  667. : provide_arguments(move(details.provide_arguments))
  668. , provide_environment(move(details.provide_environment))
  669. , provide_preopened_directories(move(details.provide_preopened_directories))
  670. {
  671. // Map all of std{in,out,err} by default.
  672. m_fd_map.insert(0, 0);
  673. m_fd_map.insert(1, 1);
  674. m_fd_map.insert(2, 2);
  675. }
  676. ErrorOr<HostFunction> function_by_name(StringView);
  677. private:
  678. template<auto impl>
  679. HostFunction invocation_of(StringView name) { return ABI::InvocationOf<impl> {}(*this, name); }
  680. ErrorOr<Result<void>> impl$args_get(Configuration&, Pointer<Pointer<u8>> argv, Pointer<u8> argv_buf);
  681. ErrorOr<Result<ArgsSizes>> impl$args_sizes_get(Configuration&);
  682. ErrorOr<Result<void>> impl$environ_get(Configuration&, Pointer<Pointer<u8>> environ, Pointer<u8> environ_buf);
  683. ErrorOr<Result<EnvironSizes>> impl$environ_sizes_get(Configuration&);
  684. ErrorOr<Result<Timestamp>> impl$clock_res_get(Configuration&, ClockID id);
  685. ErrorOr<Result<Timestamp>> impl$clock_time_get(Configuration&, ClockID id, Timestamp precision);
  686. ErrorOr<Result<void>> impl$fd_advise(Configuration&, FD, FileSize offset, FileSize len, Advice);
  687. ErrorOr<Result<void>> impl$fd_allocate(Configuration&, FD, FileSize offset, FileSize len);
  688. ErrorOr<Result<void>> impl$fd_close(Configuration&, FD);
  689. ErrorOr<Result<void>> impl$fd_datasync(Configuration&, FD);
  690. ErrorOr<Result<FDStat>> impl$fd_fdstat_get(Configuration&, FD);
  691. ErrorOr<Result<void>> impl$fd_fdstat_set_flags(Configuration&, FD, FDFlags);
  692. ErrorOr<Result<void>> impl$fd_fdstat_set_rights(Configuration&, FD, Rights fs_rights_base, Rights fs_rights_inheriting);
  693. ErrorOr<Result<FileStat>> impl$fd_filestat_get(Configuration&, FD);
  694. ErrorOr<Result<void>> impl$fd_filestat_set_size(Configuration&, FD, FileSize);
  695. ErrorOr<Result<void>> impl$fd_filestat_set_times(Configuration&, FD, Timestamp atim, Timestamp mtim, FSTFlags);
  696. ErrorOr<Result<Size>> impl$fd_pread(Configuration&, FD, Pointer<IOVec> iovs, Size iovs_len, FileSize offset);
  697. ErrorOr<Result<PreStat>> impl$fd_prestat_get(Configuration&, FD);
  698. ErrorOr<Result<void>> impl$fd_prestat_dir_name(Configuration&, FD, Pointer<u8> path, Size path_len);
  699. ErrorOr<Result<Size>> impl$fd_pwrite(Configuration&, FD, Pointer<CIOVec> iovs, Size iovs_len, FileSize offset);
  700. ErrorOr<Result<Size>> impl$fd_read(Configuration&, FD, Pointer<IOVec> iovs, Size iovs_len);
  701. ErrorOr<Result<Size>> impl$fd_readdir(Configuration&, FD, Pointer<u8> buf, Size buf_len, DirCookie cookie);
  702. ErrorOr<Result<void>> impl$fd_renumber(Configuration&, FD from, FD to);
  703. ErrorOr<Result<FileSize>> impl$fd_seek(Configuration&, FD, FileDelta offset, Whence whence);
  704. ErrorOr<Result<void>> impl$fd_sync(Configuration&, FD);
  705. ErrorOr<Result<FileSize>> impl$fd_tell(Configuration&, FD);
  706. ErrorOr<Result<Size>> impl$fd_write(Configuration&, FD, Pointer<CIOVec> iovs, Size iovs_len);
  707. ErrorOr<Result<void>> impl$path_create_directory(Configuration&, FD, Pointer<u8> path, Size path_len);
  708. ErrorOr<Result<FileStat>> impl$path_filestat_get(Configuration&, FD, LookupFlags, ConstPointer<u8> path, Size path_len);
  709. ErrorOr<Result<void>> impl$path_filestat_set_times(Configuration&, FD, LookupFlags, Pointer<u8> path, Size path_len, Timestamp atim, Timestamp mtim, FSTFlags);
  710. 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);
  711. 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);
  712. ErrorOr<Result<Size>> impl$path_readlink(Configuration&, FD, LookupFlags, Pointer<u8> path, Size path_len, Pointer<u8> buf, Size buf_len);
  713. ErrorOr<Result<void>> impl$path_remove_directory(Configuration&, FD, Pointer<u8> path, Size path_len);
  714. 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);
  715. ErrorOr<Result<void>> impl$path_symlink(Configuration&, Pointer<u8> old_path, Size old_path_len, FD, Pointer<u8> new_path, Size new_path_len);
  716. ErrorOr<Result<void>> impl$path_unlink_file(Configuration&, FD, Pointer<u8> path, Size path_len);
  717. ErrorOr<Result<Size>> impl$poll_oneoff(Configuration&, ConstPointer<Subscription> in, Pointer<Event> out, Size nsubscriptions);
  718. ErrorOr<Result<void>> impl$proc_exit(Configuration&, ExitCode); // Note: noreturn.
  719. ErrorOr<Result<void>> impl$proc_raise(Configuration&, Signal);
  720. ErrorOr<Result<void>> impl$sched_yield(Configuration&);
  721. ErrorOr<Result<void>> impl$random_get(Configuration&, Pointer<u8> buf, Size buf_len);
  722. ErrorOr<Result<FD>> impl$sock_accept(Configuration&, FD fd, FDFlags fd_flags);
  723. ErrorOr<Result<SockRecvResult>> impl$sock_recv(Configuration&, FD fd, Pointer<IOVec> ri_data, Size ri_data_len, RIFlags ri_flags);
  724. ErrorOr<Result<Size>> impl$sock_send(Configuration&, FD fd, Pointer<CIOVec> si_data, Size ri_data_len, SIFlags si_flags);
  725. ErrorOr<Result<void>> impl$sock_shutdown(Configuration&, FD fd, SDFlags how);
  726. Vector<AK::String> const& arguments() const;
  727. Vector<AK::String> const& environment() const;
  728. Vector<MappedPath> const& preopened_directories() const;
  729. using PreopenedDirectoryDescriptor = DistinctNumeric<LittleEndian<size_t>, struct PreopenedDirectoryDescriptor_tag, AK::DistinctNumericFeature::Comparison, AK::DistinctNumericFeature::CastToUnderlying, AK::DistinctNumericFeature::Increment>;
  730. using UnmappedDescriptor = DistinctNumeric<LittleEndian<size_t>, struct UnmappedDescriptor_tag, AK::DistinctNumericFeature::Comparison, AK::DistinctNumericFeature::CastToUnderlying>;
  731. using MappedDescriptor = Variant<u32, PreopenedDirectoryDescriptor>;
  732. using Descriptor = Variant<u32, PreopenedDirectoryDescriptor, UnmappedDescriptor>;
  733. Descriptor map_fd(FD);
  734. public:
  735. Function<Vector<AK::String>()> provide_arguments;
  736. Function<Vector<AK::String>()> provide_environment;
  737. Function<Vector<MappedPath>()> provide_preopened_directories;
  738. private:
  739. struct Cache {
  740. Optional<Vector<AK::String>> cached_arguments;
  741. Optional<Vector<AK::String>> cached_environment;
  742. Optional<Vector<MappedPath>> cached_preopened_directories;
  743. };
  744. mutable Cache cache {};
  745. RedBlackTree<u32, MappedDescriptor> m_fd_map;
  746. size_t m_first_unmapped_preopened_directory_index { 0 };
  747. };
  748. #undef IMPL
  749. }
  750. namespace Wasm::Wasi::ABI {
  751. template<typename T, typename... Args>
  752. struct ToCompatibleValue<DistinctNumeric<T, Args...>> {
  753. using Type = typename ToCompatibleValue<T>::Type;
  754. };
  755. template<typename T>
  756. struct ToCompatibleValue<LittleEndian<T>> {
  757. using Type = MakeSigned<T>;
  758. };
  759. template<typename T>
  760. requires(requires { declval<typename T::CompatibleType>(); })
  761. struct ToCompatibleValue<T> {
  762. using Type = MakeSigned<typename T::CompatibleType>;
  763. };
  764. template<Integral T>
  765. struct ToCompatibleValue<T> {
  766. using Type = MakeSigned<T>;
  767. };
  768. template<Enum T>
  769. struct ToCompatibleValue<T> {
  770. using Type = MakeSigned<UnderlyingType<T>>;
  771. };
  772. }
  773. template<typename T>
  774. struct AK::Formatter<Wasm::Wasi::LittleEndian<T>> : AK::Formatter<T> {
  775. ErrorOr<void> format(FormatBuilder& builder, Wasm::Wasi::LittleEndian<T> value)
  776. {
  777. return Formatter<T>::format(builder, value.operator T());
  778. }
  779. };