175fd0b74Schristos /* Utilities for reading leb128 values.
2*e992f068Schristos Copyright (C) 2012-2022 Free Software Foundation, Inc.
375fd0b74Schristos
475fd0b74Schristos This file is part of the libiberty library.
575fd0b74Schristos Libiberty is free software; you can redistribute it and/or
675fd0b74Schristos modify it under the terms of the GNU Library General Public
775fd0b74Schristos License as published by the Free Software Foundation; either
875fd0b74Schristos version 2 of the License, or (at your option) any later version.
975fd0b74Schristos
1075fd0b74Schristos Libiberty is distributed in the hope that it will be useful,
1175fd0b74Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1275fd0b74Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1375fd0b74Schristos Library General Public License for more details.
1475fd0b74Schristos
1575fd0b74Schristos You should have received a copy of the GNU Library General Public
1675fd0b74Schristos License along with libiberty; see the file COPYING.LIB. If not, write
1775fd0b74Schristos to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
1875fd0b74Schristos Boston, MA 02110-1301, USA. */
1975fd0b74Schristos
2075fd0b74Schristos /* The functions defined here can be speed critical.
2175fd0b74Schristos Since they are all pretty small we keep things simple and just define
2275fd0b74Schristos them all as "static inline".
2375fd0b74Schristos
2475fd0b74Schristos WARNING: This file is used by GDB which is stuck at C90. :-(
2575fd0b74Schristos Though it can use stdint.h, inttypes.h.
2675fd0b74Schristos Therefore if you want to add support for "long long" you need
2775fd0b74Schristos to wrap it in #ifdef CC_HAS_LONG_LONG. */
2875fd0b74Schristos
2975fd0b74Schristos #ifndef LEB128_H
3075fd0b74Schristos #define LEB128_H
3175fd0b74Schristos
3275fd0b74Schristos /* Get a definition for inline. */
3375fd0b74Schristos #include "ansidecl.h"
3475fd0b74Schristos
3575fd0b74Schristos /* Get a definition for NULL, size_t. */
3675fd0b74Schristos #include <stddef.h>
3775fd0b74Schristos
3875fd0b74Schristos #ifdef HAVE_STDINT_H
3975fd0b74Schristos #include <stdint.h>
4075fd0b74Schristos #endif
4175fd0b74Schristos #ifdef HAVE_INTTYPES_H
4275fd0b74Schristos #include <inttypes.h>
4375fd0b74Schristos #endif
4475fd0b74Schristos
4575fd0b74Schristos /* Decode the unsigned LEB128 constant at BUF into the variable pointed to
4675fd0b74Schristos by R, and return the number of bytes read.
4775fd0b74Schristos If we read off the end of the buffer, zero is returned,
4875fd0b74Schristos and nothing is stored in R.
4975fd0b74Schristos
5075fd0b74Schristos Note: The result is an int instead of a pointer to the next byte to be
5175fd0b74Schristos read to avoid const-vs-non-const problems. */
5275fd0b74Schristos
5375fd0b74Schristos static inline size_t
read_uleb128_to_uint64(const unsigned char * buf,const unsigned char * buf_end,uint64_t * r)5475fd0b74Schristos read_uleb128_to_uint64 (const unsigned char *buf, const unsigned char *buf_end,
5575fd0b74Schristos uint64_t *r)
5675fd0b74Schristos {
5775fd0b74Schristos const unsigned char *p = buf;
5875fd0b74Schristos unsigned int shift = 0;
5975fd0b74Schristos uint64_t result = 0;
6075fd0b74Schristos unsigned char byte;
6175fd0b74Schristos
6275fd0b74Schristos while (1)
6375fd0b74Schristos {
6475fd0b74Schristos if (p >= buf_end)
6575fd0b74Schristos return 0;
6675fd0b74Schristos
6775fd0b74Schristos byte = *p++;
6875fd0b74Schristos result |= ((uint64_t) (byte & 0x7f)) << shift;
6975fd0b74Schristos if ((byte & 0x80) == 0)
7075fd0b74Schristos break;
7175fd0b74Schristos shift += 7;
7275fd0b74Schristos }
7375fd0b74Schristos
7475fd0b74Schristos *r = result;
7575fd0b74Schristos return p - buf;
7675fd0b74Schristos }
7775fd0b74Schristos
7875fd0b74Schristos /* Decode the signed LEB128 constant at BUF into the variable pointed to
7975fd0b74Schristos by R, and return the number of bytes read.
8075fd0b74Schristos If we read off the end of the buffer, zero is returned,
8175fd0b74Schristos and nothing is stored in R.
8275fd0b74Schristos
8375fd0b74Schristos Note: The result is an int instead of a pointer to the next byte to be
8475fd0b74Schristos read to avoid const-vs-non-const problems. */
8575fd0b74Schristos
8675fd0b74Schristos static inline size_t
read_sleb128_to_int64(const unsigned char * buf,const unsigned char * buf_end,int64_t * r)8775fd0b74Schristos read_sleb128_to_int64 (const unsigned char *buf, const unsigned char *buf_end,
8875fd0b74Schristos int64_t *r)
8975fd0b74Schristos {
9075fd0b74Schristos const unsigned char *p = buf;
9175fd0b74Schristos unsigned int shift = 0;
9275fd0b74Schristos int64_t result = 0;
9375fd0b74Schristos unsigned char byte;
9475fd0b74Schristos
9575fd0b74Schristos while (1)
9675fd0b74Schristos {
9775fd0b74Schristos if (p >= buf_end)
9875fd0b74Schristos return 0;
9975fd0b74Schristos
10075fd0b74Schristos byte = *p++;
10175fd0b74Schristos result |= ((uint64_t) (byte & 0x7f)) << shift;
10275fd0b74Schristos shift += 7;
10375fd0b74Schristos if ((byte & 0x80) == 0)
10475fd0b74Schristos break;
10575fd0b74Schristos }
10675fd0b74Schristos if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
10775fd0b74Schristos result |= -(((uint64_t) 1) << shift);
10875fd0b74Schristos
10975fd0b74Schristos *r = result;
11075fd0b74Schristos return p - buf;
11175fd0b74Schristos }
11275fd0b74Schristos
11375fd0b74Schristos /* Return the number of bytes to read to skip past an LEB128 number in BUF.
11475fd0b74Schristos If the end isn't found before reaching BUF_END, return zero.
11575fd0b74Schristos
11675fd0b74Schristos Note: The result is an int instead of a pointer to the next byte to be
11775fd0b74Schristos read to avoid const-vs-non-const problems. */
11875fd0b74Schristos
11975fd0b74Schristos static inline size_t
skip_leb128(const unsigned char * buf,const unsigned char * buf_end)12075fd0b74Schristos skip_leb128 (const unsigned char *buf, const unsigned char *buf_end)
12175fd0b74Schristos {
12275fd0b74Schristos const unsigned char *p = buf;
12375fd0b74Schristos unsigned char byte;
12475fd0b74Schristos
12575fd0b74Schristos while (1)
12675fd0b74Schristos {
12775fd0b74Schristos if (p == buf_end)
12875fd0b74Schristos return 0;
12975fd0b74Schristos
13075fd0b74Schristos byte = *p++;
13175fd0b74Schristos if ((byte & 0x80) == 0)
13275fd0b74Schristos return p - buf;
13375fd0b74Schristos }
13475fd0b74Schristos }
13575fd0b74Schristos
13675fd0b74Schristos #endif /* LEB128_H */
137