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 18 [[noreturn]] void internal_error() { 19 printf("internal error\n"); 20 exit(1); 21 } 22 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 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 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 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 { 73 uint64_t read_zero(const unsigned char *) { return 0; } 74 75 // Read the first byte and zero/sign extend it 76 uint64_t read_embedded_u8(const unsigned char *start) { return start[0]; } 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 83 uint64_t read_via_mask_0x1(const unsigned char *start) { return *start & 0x1u; } 84 uint64_t read_via_mask_0xf(const unsigned char *start) { return *start & 0xfu; } 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. 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 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 } 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 } 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 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 } 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 } 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 } 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 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 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 { 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 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