Home | History | Annotate | Line # | Download | only in Support
      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 (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 != 0) || 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 += Slice << 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 (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     uint64_t Slice = Byte & 0x7f;
    180     if ((Shift >= 64 && Slice != (Value < 0 ? 0x7f : 0x00)) ||
    181         (Shift == 63 && Slice != 0 && Slice != 0x7f)) {
    182       if (error)
    183         *error = "sleb128 too big for int64";
    184       if (n)
    185         *n = (unsigned)(p - orig_p);
    186       return 0;
    187     }
    188     Value |= Slice << Shift;
    189     Shift += 7;
    190     ++p;
    191   } while (Byte >= 128);
    192   // Sign extend negative numbers if needed.
    193   if (Shift < 64 && (Byte & 0x40))
    194     Value |= (-1ULL) << Shift;
    195   if (n)
    196     *n = (unsigned)(p - orig_p);
    197   return Value;
    198 }
    199 
    200 /// Utility function to get the size of the ULEB128-encoded value.
    201 extern unsigned getULEB128Size(uint64_t Value);
    202 
    203 /// Utility function to get the size of the SLEB128-encoded value.
    204 extern unsigned getSLEB128Size(int64_t Value);
    205 
    206 } // namespace llvm
    207 
    208 #endif // LLVM_SUPPORT_LEB128_H
    209