• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Holder Class for manipulating va_lists ------------------*- 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 #ifndef LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
10 #define LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
11 
12 #include "src/__support/common.h"
13 
14 #include <stdarg.h>
15 #include <stddef.h>
16 #include <stdint.h>
17 
18 namespace LIBC_NAMESPACE {
19 namespace internal {
20 
21 class ArgList {
22   va_list vlist;
23 
24 public:
ArgList(va_list vlist)25   LIBC_INLINE ArgList(va_list vlist) { va_copy(this->vlist, vlist); }
ArgList(ArgList & other)26   LIBC_INLINE ArgList(ArgList &other) { va_copy(this->vlist, other.vlist); }
~ArgList()27   LIBC_INLINE ~ArgList() { va_end(this->vlist); }
28 
29   LIBC_INLINE ArgList &operator=(ArgList &rhs) {
30     va_copy(vlist, rhs.vlist);
31     return *this;
32   }
33 
next_var()34   template <class T> LIBC_INLINE T next_var() { return va_arg(vlist, T); }
35 };
36 
37 // Used for testing things that use an ArgList when it's impossible to know what
38 // the arguments should be ahead of time. An example of this would be fuzzing,
39 // since a function passed a random input could request unpredictable arguments.
40 class MockArgList {
41   size_t arg_counter = 0;
42 
43 public:
44   LIBC_INLINE MockArgList() = default;
MockArgList(va_list)45   LIBC_INLINE MockArgList(va_list) { ; }
MockArgList(MockArgList & other)46   LIBC_INLINE MockArgList(MockArgList &other) {
47     arg_counter = other.arg_counter;
48   }
49   LIBC_INLINE ~MockArgList() = default;
50 
51   LIBC_INLINE MockArgList &operator=(MockArgList &rhs) {
52     arg_counter = rhs.arg_counter;
53     return *this;
54   }
55 
next_var()56   template <class T> LIBC_INLINE T next_var() {
57     ++arg_counter;
58     return T(arg_counter);
59   }
60 
read_count()61   size_t read_count() const { return arg_counter; }
62 };
63 
64 // Used for the GPU implementation of `printf`. This models a variadic list as a
65 // simple array of pointers that are built manually by the implementation.
66 class StructArgList {
67   void *ptr;
68   void *end;
69 
70 public:
StructArgList(void * ptr,size_t size)71   LIBC_INLINE StructArgList(void *ptr, size_t size)
72       : ptr(ptr), end(reinterpret_cast<unsigned char *>(ptr) + size) {}
StructArgList(const StructArgList & other)73   LIBC_INLINE StructArgList(const StructArgList &other) {
74     ptr = other.ptr;
75     end = other.end;
76   }
77   LIBC_INLINE StructArgList() = default;
78   LIBC_INLINE ~StructArgList() = default;
79 
80   LIBC_INLINE StructArgList &operator=(const StructArgList &rhs) {
81     ptr = rhs.ptr;
82     return *this;
83   }
84 
get_ptr()85   LIBC_INLINE void *get_ptr() const { return ptr; }
86 
next_var()87   template <class T> LIBC_INLINE T next_var() {
88     ptr = reinterpret_cast<void *>(
89         ((reinterpret_cast<uintptr_t>(ptr) + alignof(T) - 1) / alignof(T)) *
90         alignof(T));
91 
92     if (ptr >= end)
93       return T(-1);
94 
95     T val = *reinterpret_cast<T *>(ptr);
96     ptr = reinterpret_cast<unsigned char *>(ptr) + sizeof(T);
97     return val;
98   }
99 };
100 
101 } // namespace internal
102 } // namespace LIBC_NAMESPACE
103 
104 #endif // LLVM_LIBC_SRC___SUPPORT_ARG_LIST_H
105