11debfc3dSmrg /* Utilities for reading leb128 values.
2*8feb0f0bSmrg Copyright (C) 2012-2020 Free Software Foundation, Inc.
31debfc3dSmrg
41debfc3dSmrg This file is part of the libiberty library.
51debfc3dSmrg Libiberty is free software; you can redistribute it and/or
61debfc3dSmrg modify it under the terms of the GNU Library General Public
71debfc3dSmrg License as published by the Free Software Foundation; either
81debfc3dSmrg version 2 of the License, or (at your option) any later version.
91debfc3dSmrg
101debfc3dSmrg Libiberty is distributed in the hope that it will be useful,
111debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
121debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
131debfc3dSmrg Library General Public License for more details.
141debfc3dSmrg
151debfc3dSmrg You should have received a copy of the GNU Library General Public
161debfc3dSmrg License along with libiberty; see the file COPYING.LIB. If not, write
171debfc3dSmrg to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
181debfc3dSmrg Boston, MA 02110-1301, USA. */
191debfc3dSmrg
201debfc3dSmrg /* The functions defined here can be speed critical.
211debfc3dSmrg Since they are all pretty small we keep things simple and just define
221debfc3dSmrg them all as "static inline".
231debfc3dSmrg
241debfc3dSmrg WARNING: This file is used by GDB which is stuck at C90. :-(
251debfc3dSmrg Though it can use stdint.h, inttypes.h.
261debfc3dSmrg Therefore if you want to add support for "long long" you need
271debfc3dSmrg to wrap it in #ifdef CC_HAS_LONG_LONG. */
281debfc3dSmrg
291debfc3dSmrg #ifndef LEB128_H
301debfc3dSmrg #define LEB128_H
311debfc3dSmrg
321debfc3dSmrg /* Get a definition for inline. */
331debfc3dSmrg #include "ansidecl.h"
341debfc3dSmrg
351debfc3dSmrg /* Get a definition for NULL, size_t. */
361debfc3dSmrg #include <stddef.h>
371debfc3dSmrg
381debfc3dSmrg #ifdef HAVE_STDINT_H
391debfc3dSmrg #include <stdint.h>
401debfc3dSmrg #endif
411debfc3dSmrg #ifdef HAVE_INTTYPES_H
421debfc3dSmrg #include <inttypes.h>
431debfc3dSmrg #endif
441debfc3dSmrg
451debfc3dSmrg /* Decode the unsigned LEB128 constant at BUF into the variable pointed to
461debfc3dSmrg by R, and return the number of bytes read.
471debfc3dSmrg If we read off the end of the buffer, zero is returned,
481debfc3dSmrg and nothing is stored in R.
491debfc3dSmrg
501debfc3dSmrg Note: The result is an int instead of a pointer to the next byte to be
511debfc3dSmrg read to avoid const-vs-non-const problems. */
521debfc3dSmrg
531debfc3dSmrg static inline size_t
read_uleb128_to_uint64(const unsigned char * buf,const unsigned char * buf_end,uint64_t * r)541debfc3dSmrg read_uleb128_to_uint64 (const unsigned char *buf, const unsigned char *buf_end,
551debfc3dSmrg uint64_t *r)
561debfc3dSmrg {
571debfc3dSmrg const unsigned char *p = buf;
581debfc3dSmrg unsigned int shift = 0;
591debfc3dSmrg uint64_t result = 0;
601debfc3dSmrg unsigned char byte;
611debfc3dSmrg
621debfc3dSmrg while (1)
631debfc3dSmrg {
641debfc3dSmrg if (p >= buf_end)
651debfc3dSmrg return 0;
661debfc3dSmrg
671debfc3dSmrg byte = *p++;
681debfc3dSmrg result |= ((uint64_t) (byte & 0x7f)) << shift;
691debfc3dSmrg if ((byte & 0x80) == 0)
701debfc3dSmrg break;
711debfc3dSmrg shift += 7;
721debfc3dSmrg }
731debfc3dSmrg
741debfc3dSmrg *r = result;
751debfc3dSmrg return p - buf;
761debfc3dSmrg }
771debfc3dSmrg
781debfc3dSmrg /* Decode the signed LEB128 constant at BUF into the variable pointed to
791debfc3dSmrg by R, and return the number of bytes read.
801debfc3dSmrg If we read off the end of the buffer, zero is returned,
811debfc3dSmrg and nothing is stored in R.
821debfc3dSmrg
831debfc3dSmrg Note: The result is an int instead of a pointer to the next byte to be
841debfc3dSmrg read to avoid const-vs-non-const problems. */
851debfc3dSmrg
861debfc3dSmrg static inline size_t
read_sleb128_to_int64(const unsigned char * buf,const unsigned char * buf_end,int64_t * r)871debfc3dSmrg read_sleb128_to_int64 (const unsigned char *buf, const unsigned char *buf_end,
881debfc3dSmrg int64_t *r)
891debfc3dSmrg {
901debfc3dSmrg const unsigned char *p = buf;
911debfc3dSmrg unsigned int shift = 0;
921debfc3dSmrg int64_t result = 0;
931debfc3dSmrg unsigned char byte;
941debfc3dSmrg
951debfc3dSmrg while (1)
961debfc3dSmrg {
971debfc3dSmrg if (p >= buf_end)
981debfc3dSmrg return 0;
991debfc3dSmrg
1001debfc3dSmrg byte = *p++;
1011debfc3dSmrg result |= ((uint64_t) (byte & 0x7f)) << shift;
1021debfc3dSmrg shift += 7;
1031debfc3dSmrg if ((byte & 0x80) == 0)
1041debfc3dSmrg break;
1051debfc3dSmrg }
1061debfc3dSmrg if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
1071debfc3dSmrg result |= -(((uint64_t) 1) << shift);
1081debfc3dSmrg
1091debfc3dSmrg *r = result;
1101debfc3dSmrg return p - buf;
1111debfc3dSmrg }
1121debfc3dSmrg
1131debfc3dSmrg /* Return the number of bytes to read to skip past an LEB128 number in BUF.
1141debfc3dSmrg If the end isn't found before reaching BUF_END, return zero.
1151debfc3dSmrg
1161debfc3dSmrg Note: The result is an int instead of a pointer to the next byte to be
1171debfc3dSmrg read to avoid const-vs-non-const problems. */
1181debfc3dSmrg
1191debfc3dSmrg static inline size_t
skip_leb128(const unsigned char * buf,const unsigned char * buf_end)1201debfc3dSmrg skip_leb128 (const unsigned char *buf, const unsigned char *buf_end)
1211debfc3dSmrg {
1221debfc3dSmrg const unsigned char *p = buf;
1231debfc3dSmrg unsigned char byte;
1241debfc3dSmrg
1251debfc3dSmrg while (1)
1261debfc3dSmrg {
1271debfc3dSmrg if (p == buf_end)
1281debfc3dSmrg return 0;
1291debfc3dSmrg
1301debfc3dSmrg byte = *p++;
1311debfc3dSmrg if ((byte & 0x80) == 0)
1321debfc3dSmrg return p - buf;
1331debfc3dSmrg }
1341debfc3dSmrg }
1351debfc3dSmrg
1361debfc3dSmrg #endif /* LEB128_H */
137