xref: /netbsd-src/external/gpl3/binutils.old/dist/include/leb128.h (revision e992f068c547fd6e84b3f104dc2340adcc955732)
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