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