1 //===--- amdgpu/impl/msgpack.cpp ---------------------------------- 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 #include <cassert>
9 #include <cstdint>
10 #include <cstring>
11 #include <functional>
12 #include <string>
13 
14 #include "msgpack.h"
15 
16 namespace msgpack {
17 
internal_error()18 [[noreturn]] void internal_error() {
19   printf("internal error\n");
20   exit(1);
21 }
22 
type_name(type ty)23 const char *type_name(type ty) {
24   switch (ty) {
25 #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
26   case NAME:                                                                   \
27     return #NAME;
28 #include "msgpack.def"
29 #undef X
30   }
31   internal_error();
32 }
33 
bytes_used_fixed(msgpack::type ty)34 unsigned bytes_used_fixed(msgpack::type ty) {
35   using namespace msgpack;
36   switch (ty) {
37 #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
38   case NAME:                                                                   \
39     return WIDTH;
40 #include "msgpack.def"
41 #undef X
42   }
43   internal_error();
44 }
45 
parse_type(unsigned char x)46 msgpack::type parse_type(unsigned char x) {
47 
48 #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
49   if (x >= LOWER && x <= UPPER) {                                              \
50     return NAME;                                                               \
51   } else
52 #include "msgpack.def"
53 #undef X
54   { internal_error(); }
55 }
56 
bitcast(T x)57 template <typename T, typename R> R bitcast(T x) {
58   static_assert(sizeof(T) == sizeof(R), "");
59   R tmp;
60   memcpy(&tmp, &x, sizeof(T));
61   return tmp;
62 }
63 template int64_t bitcast<uint64_t, int64_t>(uint64_t);
64 } // namespace msgpack
65 
66 // Helper functions for reading additional payload from the header
67 // Depending on the type, this can be a number of bytes, elements,
68 // key-value pairs or an embedded integer.
69 // Each takes a pointer to the start of the header and returns a uint64_t
70 
71 namespace {
72 namespace payload {
read_zero(const unsigned char *)73 uint64_t read_zero(const unsigned char *) { return 0; }
74 
75 // Read the first byte and zero/sign extend it
read_embedded_u8(const unsigned char * start)76 uint64_t read_embedded_u8(const unsigned char *start) { return start[0]; }
read_embedded_s8(const unsigned char * start)77 uint64_t read_embedded_s8(const unsigned char *start) {
78   int64_t res = msgpack::bitcast<uint8_t, int8_t>(start[0]);
79   return msgpack::bitcast<int64_t, uint64_t>(res);
80 }
81 
82 // Read a masked part of the first byte
read_via_mask_0x1(const unsigned char * start)83 uint64_t read_via_mask_0x1(const unsigned char *start) { return *start & 0x1u; }
read_via_mask_0xf(const unsigned char * start)84 uint64_t read_via_mask_0xf(const unsigned char *start) { return *start & 0xfu; }
read_via_mask_0x1f(const unsigned char * start)85 uint64_t read_via_mask_0x1f(const unsigned char *start) {
86   return *start & 0x1fu;
87 }
88 
89 // Read 1/2/4/8 bytes immediately following the type byte and zero/sign extend
90 // Big endian format.
read_size_field_u8(const unsigned char * from)91 uint64_t read_size_field_u8(const unsigned char *from) {
92   from++;
93   return from[0];
94 }
95 
96 // TODO: detect whether host is little endian or not, and whether the intrinsic
97 // is available. And probably use the builtin to test the diy
98 const bool use_bswap = false;
99 
read_size_field_u16(const unsigned char * from)100 uint64_t read_size_field_u16(const unsigned char *from) {
101   from++;
102   if (use_bswap) {
103     uint16_t b;
104     memcpy(&b, from, 2);
105     return __builtin_bswap16(b);
106   } else {
107     return (from[0] << 8u) | from[1];
108   }
109 }
read_size_field_u32(const unsigned char * from)110 uint64_t read_size_field_u32(const unsigned char *from) {
111   from++;
112   if (use_bswap) {
113     uint32_t b;
114     memcpy(&b, from, 4);
115     return __builtin_bswap32(b);
116   } else {
117     return (from[0] << 24u) | (from[1] << 16u) | (from[2] << 8u) |
118            (from[3] << 0u);
119   }
120 }
read_size_field_u64(const unsigned char * from)121 uint64_t read_size_field_u64(const unsigned char *from) {
122   from++;
123   if (use_bswap) {
124     uint64_t b;
125     memcpy(&b, from, 8);
126     return __builtin_bswap64(b);
127   } else {
128     return ((uint64_t)from[0] << 56u) | ((uint64_t)from[1] << 48u) |
129            ((uint64_t)from[2] << 40u) | ((uint64_t)from[3] << 32u) |
130            (from[4] << 24u) | (from[5] << 16u) | (from[6] << 8u) |
131            (from[7] << 0u);
132   }
133 }
134 
read_size_field_s8(const unsigned char * from)135 uint64_t read_size_field_s8(const unsigned char *from) {
136   uint8_t u = read_size_field_u8(from);
137   int64_t res = msgpack::bitcast<uint8_t, int8_t>(u);
138   return msgpack::bitcast<int64_t, uint64_t>(res);
139 }
read_size_field_s16(const unsigned char * from)140 uint64_t read_size_field_s16(const unsigned char *from) {
141   uint16_t u = read_size_field_u16(from);
142   int64_t res = msgpack::bitcast<uint16_t, int16_t>(u);
143   return msgpack::bitcast<int64_t, uint64_t>(res);
144 }
read_size_field_s32(const unsigned char * from)145 uint64_t read_size_field_s32(const unsigned char *from) {
146   uint32_t u = read_size_field_u32(from);
147   int64_t res = msgpack::bitcast<uint32_t, int32_t>(u);
148   return msgpack::bitcast<int64_t, uint64_t>(res);
149 }
read_size_field_s64(const unsigned char * from)150 uint64_t read_size_field_s64(const unsigned char *from) {
151   uint64_t u = read_size_field_u64(from);
152   int64_t res = msgpack::bitcast<uint64_t, int64_t>(u);
153   return msgpack::bitcast<int64_t, uint64_t>(res);
154 }
155 } // namespace payload
156 } // namespace
157 
158 namespace msgpack {
159 
payload_info(msgpack::type ty)160 payload_info_t payload_info(msgpack::type ty) {
161   using namespace msgpack;
162   switch (ty) {
163 #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
164   case NAME:                                                                   \
165     return payload::PAYLOAD;
166 #include "msgpack.def"
167 #undef X
168   }
169   internal_error();
170 }
171 
172 } // namespace msgpack
173 
skip_next_message(const unsigned char * start,const unsigned char * end)174 const unsigned char *msgpack::skip_next_message(const unsigned char *start,
175                                                 const unsigned char *end) {
176   class f : public functors_defaults<f> {};
177   return handle_msgpack({start, end}, f());
178 }
179 
180 namespace msgpack {
message_is_string(byte_range bytes,const char * needle)181 bool message_is_string(byte_range bytes, const char *needle) {
182   bool matched = false;
183   size_t needleN = strlen(needle);
184 
185   foronly_string(bytes, [=, &matched](size_t N, const unsigned char *str) {
186     if (N == needleN) {
187       if (memcmp(needle, str, N) == 0) {
188         matched = true;
189       }
190     }
191   });
192   return matched;
193 }
194 
dump(byte_range bytes)195 void dump(byte_range bytes) {
196   struct inner : functors_defaults<inner> {
197     inner(unsigned indent) : indent(indent) {}
198     const unsigned by = 2;
199     unsigned indent = 0;
200 
201     void handle_string(size_t N, const unsigned char *bytes) {
202       char *tmp = (char *)malloc(N + 1);
203       memcpy(tmp, bytes, N);
204       tmp[N] = '\0';
205       printf("\"%s\"", tmp);
206       free(tmp);
207     }
208 
209     void handle_signed(int64_t x) { printf("%ld", x); }
210     void handle_unsigned(uint64_t x) { printf("%lu", x); }
211 
212     const unsigned char *handle_array(uint64_t N, byte_range bytes) {
213       printf("\n%*s[\n", indent, "");
214       indent += by;
215 
216       for (uint64_t i = 0; i < N; i++) {
217         indent += by;
218         printf("%*s", indent, "");
219         const unsigned char *next = handle_msgpack<inner>(bytes, {indent});
220         printf(",\n");
221         indent -= by;
222         bytes.start = next;
223         if (!next) {
224           break;
225         }
226       }
227       indent -= by;
228       printf("%*s]", indent, "");
229 
230       return bytes.start;
231     }
232 
233     const unsigned char *handle_map(uint64_t N, byte_range bytes) {
234       printf("\n%*s{\n", indent, "");
235       indent += by;
236 
237       for (uint64_t i = 0; i < 2 * N; i += 2) {
238         const unsigned char *start_key = bytes.start;
239         printf("%*s", indent, "");
240         const unsigned char *end_key =
241             handle_msgpack<inner>({start_key, bytes.end}, {indent});
242         if (!end_key) {
243           break;
244         }
245 
246         printf(" : ");
247 
248         const unsigned char *start_value = end_key;
249         const unsigned char *end_value =
250             handle_msgpack<inner>({start_value, bytes.end}, {indent});
251 
252         if (!end_value) {
253           break;
254         }
255 
256         printf(",\n");
257         bytes.start = end_value;
258       }
259 
260       indent -= by;
261       printf("%*s}", indent, "");
262 
263       return bytes.start;
264     }
265   };
266 
267   handle_msgpack<inner>(bytes, {0});
268   printf("\n");
269 }
270 
271 } // namespace msgpack
272