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 19namespace llvm { 20 21/// Utility function to encode a SLEB128 value to an output stream. Returns 22/// the length in bytes of the encoded value. 23inline 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. 52inline 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. 80inline 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. 104inline 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. 128inline 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 (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. 161inline 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 (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. 191extern unsigned getULEB128Size(uint64_t Value); 192 193/// Utility function to get the size of the SLEB128-encoded value. 194extern unsigned getSLEB128Size(int64_t Value); 195 196} // namespace llvm 197 198#endif // LLVM_SYSTEM_LEB128_H 199