1239310Sdim//===- llvm/Support/LEB128.h - [SU]LEB128 utility functions -----*- C++ -*-===// 2239310Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6239310Sdim// 7239310Sdim//===----------------------------------------------------------------------===// 8239310Sdim// 9239310Sdim// This file declares some utility functions for encoding SLEB128 and 10239310Sdim// ULEB128 values. 11239310Sdim// 12239310Sdim//===----------------------------------------------------------------------===// 13239310Sdim 14249423Sdim#ifndef LLVM_SUPPORT_LEB128_H 15249423Sdim#define LLVM_SUPPORT_LEB128_H 16239310Sdim 17243830Sdim#include "llvm/Support/raw_ostream.h" 18239310Sdim 19239310Sdimnamespace llvm { 20239310Sdim 21341825Sdim/// Utility function to encode a SLEB128 value to an output stream. Returns 22341825Sdim/// the length in bytes of the encoded value. 23341825Sdiminline unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, 24341825Sdim unsigned PadTo = 0) { 25239310Sdim bool More; 26327952Sdim unsigned Count = 0; 27239310Sdim do { 28239310Sdim uint8_t Byte = Value & 0x7f; 29239310Sdim // NOTE: this assumes that this signed shift is an arithmetic right shift. 30239310Sdim Value >>= 7; 31239310Sdim More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || 32239310Sdim ((Value == -1) && ((Byte & 0x40) != 0)))); 33327952Sdim Count++; 34327952Sdim if (More || Count < PadTo) 35261991Sdim Byte |= 0x80; // Mark this byte to show that more bytes will follow. 36239310Sdim OS << char(Byte); 37239310Sdim } while (More); 38321369Sdim 39321369Sdim // Pad with 0x80 and emit a terminating byte at the end. 40327952Sdim if (Count < PadTo) { 41321369Sdim uint8_t PadValue = Value < 0 ? 0x7f : 0x00; 42327952Sdim for (; Count < PadTo - 1; ++Count) 43321369Sdim OS << char(PadValue | 0x80); 44321369Sdim OS << char(PadValue); 45341825Sdim Count++; 46321369Sdim } 47341825Sdim return Count; 48239310Sdim} 49239310Sdim 50321369Sdim/// Utility function to encode a SLEB128 value to a buffer. Returns 51321369Sdim/// the length in bytes of the encoded value. 52327952Sdiminline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0) { 53321369Sdim uint8_t *orig_p = p; 54327952Sdim unsigned Count = 0; 55321369Sdim bool More; 56321369Sdim do { 57321369Sdim uint8_t Byte = Value & 0x7f; 58321369Sdim // NOTE: this assumes that this signed shift is an arithmetic right shift. 59321369Sdim Value >>= 7; 60321369Sdim More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || 61321369Sdim ((Value == -1) && ((Byte & 0x40) != 0)))); 62327952Sdim Count++; 63327952Sdim if (More || Count < PadTo) 64321369Sdim Byte |= 0x80; // Mark this byte to show that more bytes will follow. 65321369Sdim *p++ = Byte; 66321369Sdim } while (More); 67321369Sdim 68321369Sdim // Pad with 0x80 and emit a terminating byte at the end. 69327952Sdim if (Count < PadTo) { 70321369Sdim uint8_t PadValue = Value < 0 ? 0x7f : 0x00; 71327952Sdim for (; Count < PadTo - 1; ++Count) 72321369Sdim *p++ = (PadValue | 0x80); 73321369Sdim *p++ = PadValue; 74321369Sdim } 75321369Sdim return (unsigned)(p - orig_p); 76321369Sdim} 77321369Sdim 78341825Sdim/// Utility function to encode a ULEB128 value to an output stream. Returns 79341825Sdim/// the length in bytes of the encoded value. 80341825Sdiminline unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, 81341825Sdim unsigned PadTo = 0) { 82327952Sdim unsigned Count = 0; 83239310Sdim do { 84239310Sdim uint8_t Byte = Value & 0x7f; 85239310Sdim Value >>= 7; 86327952Sdim Count++; 87327952Sdim if (Value != 0 || Count < PadTo) 88261991Sdim Byte |= 0x80; // Mark this byte to show that more bytes will follow. 89239310Sdim OS << char(Byte); 90239310Sdim } while (Value != 0); 91239310Sdim 92239310Sdim // Pad with 0x80 and emit a null byte at the end. 93327952Sdim if (Count < PadTo) { 94327952Sdim for (; Count < PadTo - 1; ++Count) 95239310Sdim OS << '\x80'; 96239310Sdim OS << '\x00'; 97327952Sdim Count++; 98239310Sdim } 99341825Sdim return Count; 100239310Sdim} 101239310Sdim 102239462Sdim/// Utility function to encode a ULEB128 value to a buffer. Returns 103239462Sdim/// the length in bytes of the encoded value. 104261991Sdiminline unsigned encodeULEB128(uint64_t Value, uint8_t *p, 105327952Sdim unsigned PadTo = 0) { 106239462Sdim uint8_t *orig_p = p; 107327952Sdim unsigned Count = 0; 108239462Sdim do { 109239462Sdim uint8_t Byte = Value & 0x7f; 110239462Sdim Value >>= 7; 111327952Sdim Count++; 112327952Sdim if (Value != 0 || Count < PadTo) 113261991Sdim Byte |= 0x80; // Mark this byte to show that more bytes will follow. 114239462Sdim *p++ = Byte; 115239462Sdim } while (Value != 0); 116239462Sdim 117239462Sdim // Pad with 0x80 and emit a null byte at the end. 118327952Sdim if (Count < PadTo) { 119327952Sdim for (; Count < PadTo - 1; ++Count) 120239462Sdim *p++ = '\x80'; 121239462Sdim *p++ = '\x00'; 122239462Sdim } 123327952Sdim 124239462Sdim return (unsigned)(p - orig_p); 125239462Sdim} 126239462Sdim 127239462Sdim/// Utility function to decode a ULEB128 value. 128321369Sdiminline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr, 129321369Sdim const uint8_t *end = nullptr, 130321369Sdim const char **error = nullptr) { 131239462Sdim const uint8_t *orig_p = p; 132239462Sdim uint64_t Value = 0; 133239462Sdim unsigned Shift = 0; 134321369Sdim if (error) 135321369Sdim *error = nullptr; 136239462Sdim do { 137321369Sdim if (end && p == end) { 138321369Sdim if (error) 139321369Sdim *error = "malformed uleb128, extends past end"; 140321369Sdim if (n) 141321369Sdim *n = (unsigned)(p - orig_p); 142321369Sdim return 0; 143321369Sdim } 144321369Sdim uint64_t Slice = *p & 0x7f; 145321369Sdim if (Shift >= 64 || Slice << Shift >> Shift != Slice) { 146321369Sdim if (error) 147321369Sdim *error = "uleb128 too big for uint64"; 148321369Sdim if (n) 149321369Sdim *n = (unsigned)(p - orig_p); 150321369Sdim return 0; 151321369Sdim } 152280031Sdim Value += uint64_t(*p & 0x7f) << Shift; 153239462Sdim Shift += 7; 154239462Sdim } while (*p++ >= 128); 155239462Sdim if (n) 156239462Sdim *n = (unsigned)(p - orig_p); 157239462Sdim return Value; 158239462Sdim} 159239462Sdim 160280031Sdim/// Utility function to decode a SLEB128 value. 161321369Sdiminline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr, 162321369Sdim const uint8_t *end = nullptr, 163321369Sdim const char **error = nullptr) { 164280031Sdim const uint8_t *orig_p = p; 165280031Sdim int64_t Value = 0; 166280031Sdim unsigned Shift = 0; 167280031Sdim uint8_t Byte; 168353358Sdim if (error) 169353358Sdim *error = nullptr; 170280031Sdim do { 171321369Sdim if (end && p == end) { 172321369Sdim if (error) 173321369Sdim *error = "malformed sleb128, extends past end"; 174321369Sdim if (n) 175321369Sdim *n = (unsigned)(p - orig_p); 176321369Sdim return 0; 177321369Sdim } 178280031Sdim Byte = *p++; 179353358Sdim Value |= (uint64_t(Byte & 0x7f) << Shift); 180280031Sdim Shift += 7; 181280031Sdim } while (Byte >= 128); 182353358Sdim // Sign extend negative numbers if needed. 183353358Sdim if (Shift < 64 && (Byte & 0x40)) 184280031Sdim Value |= (-1ULL) << Shift; 185280031Sdim if (n) 186280031Sdim *n = (unsigned)(p - orig_p); 187280031Sdim return Value; 188280031Sdim} 189280031Sdim 190276479Sdim/// Utility function to get the size of the ULEB128-encoded value. 191276479Sdimextern unsigned getULEB128Size(uint64_t Value); 192276479Sdim 193276479Sdim/// Utility function to get the size of the SLEB128-encoded value. 194276479Sdimextern unsigned getSLEB128Size(int64_t Value); 195276479Sdim 196321369Sdim} // namespace llvm 197239310Sdim 198321369Sdim#endif // LLVM_SYSTEM_LEB128_H 199