1 //===- llvm/Support/LEB128.h - [SU]LEB128 utility functions -----*- 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 declares some utility functions for encoding SLEB128 and 10 // ULEB128 values. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_SUPPORT_LEB128_H 15 #define LLVM_SUPPORT_LEB128_H 16 17 #include "llvm/Support/raw_ostream.h" 18 19 namespace llvm { 20 21 /// Utility function to encode a SLEB128 value to an output stream. Returns 22 /// the length in bytes of the encoded value. 23 inline unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, 24 unsigned PadTo = 0) { 25 bool More; 26 unsigned Count = 0; 27 do { 28 uint8_t Byte = Value & 0x7f; 29 // NOTE: this assumes that this signed shift is an arithmetic right shift. 30 Value >>= 7; 31 More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || 32 ((Value == -1) && ((Byte & 0x40) != 0)))); 33 Count++; 34 if (More || Count < PadTo) 35 Byte |= 0x80; // Mark this byte to show that more bytes will follow. 36 OS << char(Byte); 37 } while (More); 38 39 // Pad with 0x80 and emit a terminating byte at the end. 40 if (Count < PadTo) { 41 uint8_t PadValue = Value < 0 ? 0x7f : 0x00; 42 for (; Count < PadTo - 1; ++Count) 43 OS << char(PadValue | 0x80); 44 OS << char(PadValue); 45 Count++; 46 } 47 return Count; 48 } 49 50 /// Utility function to encode a SLEB128 value to a buffer. Returns 51 /// the length in bytes of the encoded value. 52 inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0) { 53 uint8_t *orig_p = p; 54 unsigned Count = 0; 55 bool More; 56 do { 57 uint8_t Byte = Value & 0x7f; 58 // NOTE: this assumes that this signed shift is an arithmetic right shift. 59 Value >>= 7; 60 More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || 61 ((Value == -1) && ((Byte & 0x40) != 0)))); 62 Count++; 63 if (More || Count < PadTo) 64 Byte |= 0x80; // Mark this byte to show that more bytes will follow. 65 *p++ = Byte; 66 } while (More); 67 68 // Pad with 0x80 and emit a terminating byte at the end. 69 if (Count < PadTo) { 70 uint8_t PadValue = Value < 0 ? 0x7f : 0x00; 71 for (; Count < PadTo - 1; ++Count) 72 *p++ = (PadValue | 0x80); 73 *p++ = PadValue; 74 } 75 return (unsigned)(p - orig_p); 76 } 77 78 /// Utility function to encode a ULEB128 value to an output stream. Returns 79 /// the length in bytes of the encoded value. 80 inline unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, 81 unsigned PadTo = 0) { 82 unsigned Count = 0; 83 do { 84 uint8_t Byte = Value & 0x7f; 85 Value >>= 7; 86 Count++; 87 if (Value != 0 || Count < PadTo) 88 Byte |= 0x80; // Mark this byte to show that more bytes will follow. 89 OS << char(Byte); 90 } while (Value != 0); 91 92 // Pad with 0x80 and emit a null byte at the end. 93 if (Count < PadTo) { 94 for (; Count < PadTo - 1; ++Count) 95 OS << '\x80'; 96 OS << '\x00'; 97 Count++; 98 } 99 return Count; 100 } 101 102 /// Utility function to encode a ULEB128 value to a buffer. Returns 103 /// the length in bytes of the encoded value. 104 inline unsigned encodeULEB128(uint64_t Value, uint8_t *p, 105 unsigned PadTo = 0) { 106 uint8_t *orig_p = p; 107 unsigned Count = 0; 108 do { 109 uint8_t Byte = Value & 0x7f; 110 Value >>= 7; 111 Count++; 112 if (Value != 0 || Count < PadTo) 113 Byte |= 0x80; // Mark this byte to show that more bytes will follow. 114 *p++ = Byte; 115 } while (Value != 0); 116 117 // Pad with 0x80 and emit a null byte at the end. 118 if (Count < PadTo) { 119 for (; Count < PadTo - 1; ++Count) 120 *p++ = '\x80'; 121 *p++ = '\x00'; 122 } 123 124 return (unsigned)(p - orig_p); 125 } 126 127 /// Utility function to decode a ULEB128 value. 128 inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr, 129 const uint8_t *end = nullptr, 130 const char **error = nullptr) { 131 const uint8_t *orig_p = p; 132 uint64_t Value = 0; 133 unsigned Shift = 0; 134 if (error) 135 *error = nullptr; 136 do { 137 if (end && p == end) { 138 if (error) 139 *error = "malformed uleb128, extends past end"; 140 if (n) 141 *n = (unsigned)(p - orig_p); 142 return 0; 143 } 144 uint64_t Slice = *p & 0x7f; 145 if (Shift >= 64 || Slice << Shift >> Shift != Slice) { 146 if (error) 147 *error = "uleb128 too big for uint64"; 148 if (n) 149 *n = (unsigned)(p - orig_p); 150 return 0; 151 } 152 Value += uint64_t(*p & 0x7f) << Shift; 153 Shift += 7; 154 } while (*p++ >= 128); 155 if (n) 156 *n = (unsigned)(p - orig_p); 157 return Value; 158 } 159 160 /// Utility function to decode a SLEB128 value. 161 inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr, 162 const uint8_t *end = nullptr, 163 const char **error = nullptr) { 164 const uint8_t *orig_p = p; 165 int64_t Value = 0; 166 unsigned Shift = 0; 167 uint8_t Byte; 168 if (error) 169 *error = nullptr; 170 do { 171 if (end && p == end) { 172 if (error) 173 *error = "malformed sleb128, extends past end"; 174 if (n) 175 *n = (unsigned)(p - orig_p); 176 return 0; 177 } 178 Byte = *p++; 179 Value |= (uint64_t(Byte & 0x7f) << Shift); 180 Shift += 7; 181 } while (Byte >= 128); 182 // Sign extend negative numbers if needed. 183 if (Shift < 64 && (Byte & 0x40)) 184 Value |= (-1ULL) << Shift; 185 if (n) 186 *n = (unsigned)(p - orig_p); 187 return Value; 188 } 189 190 /// Utility function to get the size of the ULEB128-encoded value. 191 extern unsigned getULEB128Size(uint64_t Value); 192 193 /// Utility function to get the size of the SLEB128-encoded value. 194 extern unsigned getSLEB128Size(int64_t Value); 195 196 } // namespace llvm 197 198 #endif // LLVM_SYSTEM_LEB128_H 199