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