xref: /freebsd/contrib/llvm-project/libc/src/__support/RPC/rpc_server.h (revision bb722a7d0f1642bff6487f943ad0427799a6e5bf)
1 //===-- Shared memory RPC server instantiation ------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is intended to be used externally as part of the `shared/`
10 // interface. For that purpose, we manually define a few options normally
11 // handled by the libc build system.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_LIBC_SRC___SUPPORT_RPC_RPC_SERVER_H
16 #define LLVM_LIBC_SRC___SUPPORT_RPC_RPC_SERVER_H
17 
18 // Workaround for missing __has_builtin in < GCC 10.
19 #ifndef __has_builtin
20 #define __has_builtin(x) 0
21 #endif
22 
23 // Workaround for missing __builtin_is_constant_evaluated in < GCC 10.
24 #ifndef __builtin_is_constant_evaluated
25 #define __builtin_is_constant_evaluated(x) 0
26 #endif
27 
28 // Configs for using the LLVM libc writer interface.
29 #define LIBC_COPT_USE_C_ASSERT
30 #define LIBC_COPT_MEMCPY_USE_EMBEDDED_TINY
31 #define LIBC_COPT_ARRAY_ARG_LIST
32 #define LIBC_COPT_PRINTF_DISABLE_WRITE_INT
33 #define LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
34 #define LIBC_COPT_PRINTF_DISABLE_STRERROR
35 
36 // The 'long double' type is 8 bytes.
37 #define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64
38 
39 #include "shared/rpc.h"
40 #include "shared/rpc_opcodes.h"
41 
42 #include "src/__support/arg_list.h"
43 #include "src/stdio/printf_core/converter.h"
44 #include "src/stdio/printf_core/parser.h"
45 #include "src/stdio/printf_core/writer.h"
46 
47 #include "hdr/stdio_overlay.h"
48 #include "hdr/stdlib_overlay.h"
49 
50 namespace LIBC_NAMESPACE_DECL {
51 namespace internal {
52 
53 // Minimal replacement for 'std::vector' that works for trivial types.
54 template <typename T> class TempVector {
55   static_assert(cpp::is_trivially_constructible<T>::value &&
56                     cpp::is_trivially_destructible<T>::value,
57                 "Not a trivial type.");
58   T *data;
59   size_t current;
60   size_t capacity;
61 
62 public:
TempVector()63   LIBC_INLINE TempVector() : data(nullptr), current(0), capacity(0) {}
64 
~TempVector()65   LIBC_INLINE ~TempVector() { free(data); }
66 
push_back(const T & value)67   LIBC_INLINE void push_back(const T &value) {
68     if (current == capacity)
69       grow();
70     data[current] = T(value);
71     ++current;
72   }
73 
push_back(T && value)74   LIBC_INLINE void push_back(T &&value) {
75     if (current == capacity)
76       grow();
77     data[current] = T(static_cast<T &&>(value));
78     ++current;
79   }
80 
pop_back()81   LIBC_INLINE void pop_back() { --current; }
82 
empty()83   LIBC_INLINE bool empty() { return current == 0; }
84 
size()85   LIBC_INLINE size_t size() { return current; }
86 
87   LIBC_INLINE T &operator[](size_t index) { return data[index]; }
88 
back()89   LIBC_INLINE T &back() { return data[current - 1]; }
90 
91 private:
grow()92   LIBC_INLINE void grow() {
93     size_t new_capacity = capacity ? capacity * 2 : 1;
94     void *new_data = realloc(data, new_capacity * sizeof(T));
95     data = static_cast<T *>(new_data);
96     capacity = new_capacity;
97   }
98 };
99 
100 struct TempStorage {
allocTempStorage101   LIBC_INLINE char *alloc(size_t size) {
102     storage.push_back(reinterpret_cast<char *>(malloc(size)));
103     return storage.back();
104   }
105 
~TempStorageTempStorage106   LIBC_INLINE ~TempStorage() {
107     for (size_t i = 0; i < storage.size(); ++i)
108       free(storage[i]);
109   }
110 
111   TempVector<char *> storage;
112 };
113 
114 // Get the associated stream out of an encoded number.
to_stream(uintptr_t f)115 LIBC_INLINE static ::FILE *to_stream(uintptr_t f) {
116   enum Stream {
117     File = 0,
118     Stdin = 1,
119     Stdout = 2,
120     Stderr = 3,
121   };
122 
123   ::FILE *stream = reinterpret_cast<FILE *>(f & ~0x3ull);
124   Stream type = static_cast<Stream>(f & 0x3ull);
125   if (type == Stdin)
126     return stdin;
127   if (type == Stdout)
128     return stdout;
129   if (type == Stderr)
130     return stderr;
131   return stream;
132 }
133 
134 template <bool packed, uint32_t num_lanes>
handle_printf(rpc::Server::Port & port,TempStorage & temp_storage)135 LIBC_INLINE static void handle_printf(rpc::Server::Port &port,
136                                       TempStorage &temp_storage) {
137   FILE *files[num_lanes] = {nullptr};
138   // Get the appropriate output stream to use.
139   if (port.get_opcode() == LIBC_PRINTF_TO_STREAM ||
140       port.get_opcode() == LIBC_PRINTF_TO_STREAM_PACKED) {
141     port.recv([&](rpc::Buffer *buffer, uint32_t id) {
142       files[id] = reinterpret_cast<FILE *>(buffer->data[0]);
143     });
144   } else if (port.get_opcode() == LIBC_PRINTF_TO_STDOUT ||
145              port.get_opcode() == LIBC_PRINTF_TO_STDOUT_PACKED) {
146     for (uint32_t i = 0; i < num_lanes; ++i)
147       files[i] = stdout;
148   } else {
149     for (uint32_t i = 0; i < num_lanes; ++i)
150       files[i] = stderr;
151   }
152 
153   uint64_t format_sizes[num_lanes] = {0};
154   void *format[num_lanes] = {nullptr};
155 
156   uint64_t args_sizes[num_lanes] = {0};
157   void *args[num_lanes] = {nullptr};
158 
159   // Recieve the format string and arguments from the client.
160   port.recv_n(format, format_sizes,
161               [&](uint64_t size) { return temp_storage.alloc(size); });
162 
163   // Parse the format string to get the expected size of the buffer.
164   for (uint32_t lane = 0; lane < num_lanes; ++lane) {
165     if (!format[lane])
166       continue;
167 
168     printf_core::WriteBuffer<
169         printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
170         wb(nullptr, 0);
171     printf_core::Writer writer(wb);
172 
173     internal::DummyArgList<packed> printf_args;
174     printf_core::Parser<internal::DummyArgList<packed> &> parser(
175         reinterpret_cast<const char *>(format[lane]), printf_args);
176 
177     for (printf_core::FormatSection cur_section = parser.get_next_section();
178          !cur_section.raw_string.empty();
179          cur_section = parser.get_next_section())
180       ;
181     args_sizes[lane] = printf_args.read_count();
182   }
183   port.send([&](rpc::Buffer *buffer, uint32_t id) {
184     buffer->data[0] = args_sizes[id];
185   });
186   port.recv_n(args, args_sizes,
187               [&](uint64_t size) { return temp_storage.alloc(size); });
188 
189   // Identify any arguments that are actually pointers to strings on the client.
190   // Additionally we want to determine how much buffer space we need to print.
191   TempVector<void *> strs_to_copy[num_lanes];
192   int buffer_size[num_lanes] = {0};
193   for (uint32_t lane = 0; lane < num_lanes; ++lane) {
194     if (!format[lane])
195       continue;
196 
197     printf_core::WriteBuffer<
198         printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
199         wb(nullptr, 0);
200     printf_core::Writer writer(wb);
201 
202     internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]);
203     printf_core::Parser<internal::StructArgList<packed>> parser(
204         reinterpret_cast<const char *>(format[lane]), printf_args);
205 
206     for (printf_core::FormatSection cur_section = parser.get_next_section();
207          !cur_section.raw_string.empty();
208          cur_section = parser.get_next_section()) {
209       if (cur_section.has_conv && cur_section.conv_name == 's' &&
210           cur_section.conv_val_ptr) {
211         strs_to_copy[lane].push_back(cur_section.conv_val_ptr);
212         // Get the minimum size of the string in the case of padding.
213         char c = '\0';
214         cur_section.conv_val_ptr = &c;
215         convert(&writer, cur_section);
216       } else if (cur_section.has_conv) {
217         // Ignore conversion errors for the first pass.
218         convert(&writer, cur_section);
219       } else {
220         writer.write(cur_section.raw_string);
221       }
222     }
223     buffer_size[lane] = writer.get_chars_written();
224   }
225 
226   // Recieve any strings from the client and push them into a buffer.
227   TempVector<void *> copied_strs[num_lanes];
228   auto HasPendingCopies = [](TempVector<void *> v[num_lanes]) {
229     for (uint32_t i = 0; i < num_lanes; ++i)
230       if (!v[i].empty() && v[i].back())
231         return true;
232     return false;
233   };
234   while (HasPendingCopies(strs_to_copy)) {
235     port.send([&](rpc::Buffer *buffer, uint32_t id) {
236       void *ptr = !strs_to_copy[id].empty() ? strs_to_copy[id].back() : nullptr;
237       buffer->data[1] = reinterpret_cast<uintptr_t>(ptr);
238       if (!strs_to_copy[id].empty())
239         strs_to_copy[id].pop_back();
240     });
241     uint64_t str_sizes[num_lanes] = {0};
242     void *strs[num_lanes] = {nullptr};
243     port.recv_n(strs, str_sizes,
244                 [&](uint64_t size) { return temp_storage.alloc(size); });
245     for (uint32_t lane = 0; lane < num_lanes; ++lane) {
246       if (!strs[lane])
247         continue;
248 
249       copied_strs[lane].push_back(strs[lane]);
250       buffer_size[lane] += str_sizes[lane];
251     }
252   }
253 
254   // Perform the final formatting and printing using the LLVM C library printf.
255   int results[num_lanes] = {0};
256   for (uint32_t lane = 0; lane < num_lanes; ++lane) {
257     if (!format[lane])
258       continue;
259 
260     char *buffer = temp_storage.alloc(buffer_size[lane]);
261     printf_core::WriteBuffer<
262         printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
263         wb(buffer, buffer_size[lane]);
264     printf_core::Writer writer(wb);
265 
266     internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]);
267     printf_core::Parser<internal::StructArgList<packed>> parser(
268         reinterpret_cast<const char *>(format[lane]), printf_args);
269 
270     // Parse and print the format string using the arguments we copied from
271     // the client.
272     int ret = 0;
273     for (printf_core::FormatSection cur_section = parser.get_next_section();
274          !cur_section.raw_string.empty();
275          cur_section = parser.get_next_section()) {
276       // If this argument was a string we use the memory buffer we copied from
277       // the client by replacing the raw pointer with the copied one.
278       if (cur_section.has_conv && cur_section.conv_name == 's') {
279         if (!copied_strs[lane].empty()) {
280           cur_section.conv_val_ptr = copied_strs[lane].back();
281           copied_strs[lane].pop_back();
282         } else {
283           cur_section.conv_val_ptr = nullptr;
284         }
285       }
286       if (cur_section.has_conv) {
287         ret = convert(&writer, cur_section);
288         if (ret == -1)
289           break;
290       } else {
291         writer.write(cur_section.raw_string);
292       }
293     }
294 
295     results[lane] = static_cast<int>(
296         fwrite(buffer, 1, writer.get_chars_written(), files[lane]));
297     if (results[lane] != writer.get_chars_written() || ret == -1)
298       results[lane] = -1;
299   }
300 
301   // Send the final return value and signal completion by setting the string
302   // argument to null.
303   port.send([&](rpc::Buffer *buffer, uint32_t id) {
304     buffer->data[0] = static_cast<uint64_t>(results[id]);
305     buffer->data[1] = reinterpret_cast<uintptr_t>(nullptr);
306   });
307 }
308 
309 template <uint32_t num_lanes>
handle_port_impl(rpc::Server::Port & port)310 LIBC_INLINE static rpc::Status handle_port_impl(rpc::Server::Port &port) {
311   TempStorage temp_storage;
312 
313   switch (port.get_opcode()) {
314   case LIBC_WRITE_TO_STREAM:
315   case LIBC_WRITE_TO_STDERR:
316   case LIBC_WRITE_TO_STDOUT:
317   case LIBC_WRITE_TO_STDOUT_NEWLINE: {
318     uint64_t sizes[num_lanes] = {0};
319     void *strs[num_lanes] = {nullptr};
320     FILE *files[num_lanes] = {nullptr};
321     if (port.get_opcode() == LIBC_WRITE_TO_STREAM) {
322       port.recv([&](rpc::Buffer *buffer, uint32_t id) {
323         files[id] = reinterpret_cast<FILE *>(buffer->data[0]);
324       });
325     } else {
326       for (uint32_t i = 0; i < num_lanes; ++i)
327         files[i] = port.get_opcode() == LIBC_WRITE_TO_STDERR ? stderr : stdout;
328     }
329 
330     port.recv_n(strs, sizes,
331                 [&](uint64_t size) { return temp_storage.alloc(size); });
332     port.send([&](rpc::Buffer *buffer, uint32_t id) {
333       flockfile(files[id]);
334       buffer->data[0] = fwrite_unlocked(strs[id], 1, sizes[id], files[id]);
335       if (port.get_opcode() == LIBC_WRITE_TO_STDOUT_NEWLINE &&
336           buffer->data[0] == sizes[id])
337         buffer->data[0] += fwrite_unlocked("\n", 1, 1, files[id]);
338       funlockfile(files[id]);
339     });
340     break;
341   }
342   case LIBC_READ_FROM_STREAM: {
343     uint64_t sizes[num_lanes] = {0};
344     void *data[num_lanes] = {nullptr};
345     port.recv([&](rpc::Buffer *buffer, uint32_t id) {
346       data[id] = temp_storage.alloc(buffer->data[0]);
347       sizes[id] =
348           fread(data[id], 1, buffer->data[0], to_stream(buffer->data[1]));
349     });
350     port.send_n(data, sizes);
351     port.send([&](rpc::Buffer *buffer, uint32_t id) {
352       __builtin_memcpy(buffer->data, &sizes[id], sizeof(uint64_t));
353     });
354     break;
355   }
356   case LIBC_READ_FGETS: {
357     uint64_t sizes[num_lanes] = {0};
358     void *data[num_lanes] = {nullptr};
359     port.recv([&](rpc::Buffer *buffer, uint32_t id) {
360       data[id] = temp_storage.alloc(buffer->data[0]);
361       const char *str = ::fgets(reinterpret_cast<char *>(data[id]),
362                                 static_cast<int>(buffer->data[0]),
363                                 to_stream(buffer->data[1]));
364       sizes[id] = !str ? 0 : __builtin_strlen(str) + 1;
365     });
366     port.send_n(data, sizes);
367     break;
368   }
369   case LIBC_OPEN_FILE: {
370     uint64_t sizes[num_lanes] = {0};
371     void *paths[num_lanes] = {nullptr};
372     port.recv_n(paths, sizes,
373                 [&](uint64_t size) { return temp_storage.alloc(size); });
374     port.recv_and_send([&](rpc::Buffer *buffer, uint32_t id) {
375       FILE *file = fopen(reinterpret_cast<char *>(paths[id]),
376                          reinterpret_cast<char *>(buffer->data));
377       buffer->data[0] = reinterpret_cast<uintptr_t>(file);
378     });
379     break;
380   }
381   case LIBC_CLOSE_FILE: {
382     port.recv_and_send([&](rpc::Buffer *buffer, uint32_t) {
383       FILE *file = reinterpret_cast<FILE *>(buffer->data[0]);
384       buffer->data[0] = ::fclose(file);
385     });
386     break;
387   }
388   case LIBC_EXIT: {
389     // Send a response to the client to signal that we are ready to exit.
390     port.recv_and_send([](rpc::Buffer *, uint32_t) {});
391     port.recv([](rpc::Buffer *buffer, uint32_t) {
392       int status = 0;
393       __builtin_memcpy(&status, buffer->data, sizeof(int));
394       exit(status);
395     });
396     break;
397   }
398   case LIBC_ABORT: {
399     // Send a response to the client to signal that we are ready to abort.
400     port.recv_and_send([](rpc::Buffer *, uint32_t) {});
401     port.recv([](rpc::Buffer *, uint32_t) {});
402     abort();
403     break;
404   }
405   case LIBC_HOST_CALL: {
406     uint64_t sizes[num_lanes] = {0};
407     unsigned long long results[num_lanes] = {0};
408     void *args[num_lanes] = {nullptr};
409     port.recv_n(args, sizes,
410                 [&](uint64_t size) { return temp_storage.alloc(size); });
411     port.recv([&](rpc::Buffer *buffer, uint32_t id) {
412       using func_ptr_t = unsigned long long (*)(void *);
413       auto func = reinterpret_cast<func_ptr_t>(buffer->data[0]);
414       results[id] = func(args[id]);
415     });
416     port.send([&](rpc::Buffer *buffer, uint32_t id) {
417       buffer->data[0] = static_cast<uint64_t>(results[id]);
418     });
419     break;
420   }
421   case LIBC_FEOF: {
422     port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
423       buffer->data[0] = feof(to_stream(buffer->data[0]));
424     });
425     break;
426   }
427   case LIBC_FERROR: {
428     port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
429       buffer->data[0] = ferror(to_stream(buffer->data[0]));
430     });
431     break;
432   }
433   case LIBC_CLEARERR: {
434     port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
435       clearerr(to_stream(buffer->data[0]));
436     });
437     break;
438   }
439   case LIBC_FSEEK: {
440     port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
441       buffer->data[0] =
442           fseek(to_stream(buffer->data[0]), static_cast<long>(buffer->data[1]),
443                 static_cast<int>(buffer->data[2]));
444     });
445     break;
446   }
447   case LIBC_FTELL: {
448     port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
449       buffer->data[0] = ftell(to_stream(buffer->data[0]));
450     });
451     break;
452   }
453   case LIBC_FFLUSH: {
454     port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
455       buffer->data[0] = fflush(to_stream(buffer->data[0]));
456     });
457     break;
458   }
459   case LIBC_UNGETC: {
460     port.recv_and_send([](rpc::Buffer *buffer, uint32_t) {
461       buffer->data[0] =
462           ungetc(static_cast<int>(buffer->data[0]), to_stream(buffer->data[1]));
463     });
464     break;
465   }
466   case LIBC_PRINTF_TO_STREAM_PACKED:
467   case LIBC_PRINTF_TO_STDOUT_PACKED:
468   case LIBC_PRINTF_TO_STDERR_PACKED: {
469     handle_printf<true, num_lanes>(port, temp_storage);
470     break;
471   }
472   case LIBC_PRINTF_TO_STREAM:
473   case LIBC_PRINTF_TO_STDOUT:
474   case LIBC_PRINTF_TO_STDERR: {
475     handle_printf<false, num_lanes>(port, temp_storage);
476     break;
477   }
478   case LIBC_REMOVE: {
479     uint64_t sizes[num_lanes] = {0};
480     void *args[num_lanes] = {nullptr};
481     port.recv_n(args, sizes,
482                 [&](uint64_t size) { return temp_storage.alloc(size); });
483     port.send([&](rpc::Buffer *buffer, uint32_t id) {
484       buffer->data[0] = static_cast<uint64_t>(
485           remove(reinterpret_cast<const char *>(args[id])));
486     });
487     break;
488   }
489   case LIBC_RENAME: {
490     uint64_t oldsizes[num_lanes] = {0};
491     uint64_t newsizes[num_lanes] = {0};
492     void *oldpath[num_lanes] = {nullptr};
493     void *newpath[num_lanes] = {nullptr};
494     port.recv_n(oldpath, oldsizes,
495                 [&](uint64_t size) { return temp_storage.alloc(size); });
496     port.recv_n(newpath, newsizes,
497                 [&](uint64_t size) { return temp_storage.alloc(size); });
498     port.send([&](rpc::Buffer *buffer, uint32_t id) {
499       buffer->data[0] = static_cast<uint64_t>(
500           rename(reinterpret_cast<const char *>(oldpath[id]),
501                  reinterpret_cast<const char *>(newpath[id])));
502     });
503     break;
504   }
505   case LIBC_SYSTEM: {
506     uint64_t sizes[num_lanes] = {0};
507     void *args[num_lanes] = {nullptr};
508     port.recv_n(args, sizes,
509                 [&](uint64_t size) { return temp_storage.alloc(size); });
510     port.send([&](rpc::Buffer *buffer, uint32_t id) {
511       buffer->data[0] = static_cast<uint64_t>(
512           system(reinterpret_cast<const char *>(args[id])));
513     });
514     break;
515   }
516   case LIBC_NOOP: {
517     port.recv([](rpc::Buffer *, uint32_t) {});
518     break;
519   }
520   default:
521     return rpc::RPC_UNHANDLED_OPCODE;
522   }
523 
524   return rpc::RPC_SUCCESS;
525 }
526 
527 } // namespace internal
528 } // namespace LIBC_NAMESPACE_DECL
529 
530 namespace LIBC_NAMESPACE_DECL {
531 namespace rpc {
532 
533 // Handles any opcode generated from the 'libc' client code.
handle_libc_opcodes(::rpc::Server::Port & port,uint32_t num_lanes)534 LIBC_INLINE ::rpc::Status handle_libc_opcodes(::rpc::Server::Port &port,
535                                               uint32_t num_lanes) {
536   switch (num_lanes) {
537   case 1:
538     return internal::handle_port_impl<1>(port);
539   case 32:
540     return internal::handle_port_impl<32>(port);
541   case 64:
542     return internal::handle_port_impl<64>(port);
543   default:
544     return ::rpc::RPC_ERROR;
545   }
546 }
547 
548 } // namespace rpc
549 } // namespace LIBC_NAMESPACE_DECL
550 
551 #endif // LLVM_LIBC_SRC___SUPPORT_RPC_RPC_SERVER_H
552