xref: /netbsd-src/external/gpl3/gdb/dist/include/leb128.h (revision e663ba6e3a60083e70de702e9d54bf486a57b6a7)
1a2e2270fSchristos /* Utilities for reading leb128 values.
2*e663ba6eSchristos    Copyright (C) 2012-2024 Free Software Foundation, Inc.
3a2e2270fSchristos 
4a2e2270fSchristos This file is part of the libiberty library.
5a2e2270fSchristos Libiberty is free software; you can redistribute it and/or
6a2e2270fSchristos modify it under the terms of the GNU Library General Public
7a2e2270fSchristos License as published by the Free Software Foundation; either
8a2e2270fSchristos version 2 of the License, or (at your option) any later version.
9a2e2270fSchristos 
10a2e2270fSchristos Libiberty is distributed in the hope that it will be useful,
11a2e2270fSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
12a2e2270fSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13a2e2270fSchristos Library General Public License for more details.
14a2e2270fSchristos 
15a2e2270fSchristos You should have received a copy of the GNU Library General Public
16a2e2270fSchristos License along with libiberty; see the file COPYING.LIB.  If not, write
17a2e2270fSchristos to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
18a2e2270fSchristos Boston, MA 02110-1301, USA.  */
19a2e2270fSchristos 
20a2e2270fSchristos /* The functions defined here can be speed critical.
21a2e2270fSchristos    Since they are all pretty small we keep things simple and just define
22a2e2270fSchristos    them all as "static inline".
23a2e2270fSchristos 
24a2e2270fSchristos    WARNING: This file is used by GDB which is stuck at C90. :-(
25a2e2270fSchristos    Though it can use stdint.h, inttypes.h.
26a2e2270fSchristos    Therefore if you want to add support for "long long" you need
27a2e2270fSchristos    to wrap it in #ifdef CC_HAS_LONG_LONG.  */
28a2e2270fSchristos 
29a2e2270fSchristos #ifndef LEB128_H
30a2e2270fSchristos #define LEB128_H
31a2e2270fSchristos 
32a2e2270fSchristos /* Get a definition for inline.  */
33a2e2270fSchristos #include "ansidecl.h"
34a2e2270fSchristos 
35a2e2270fSchristos /* Get a definition for NULL, size_t.  */
36a2e2270fSchristos #include <stddef.h>
37a2e2270fSchristos 
38a2e2270fSchristos #ifdef HAVE_STDINT_H
39a2e2270fSchristos #include <stdint.h>
40a2e2270fSchristos #endif
41a2e2270fSchristos #ifdef HAVE_INTTYPES_H
42a2e2270fSchristos #include <inttypes.h>
43a2e2270fSchristos #endif
44a2e2270fSchristos 
45a2e2270fSchristos /* Decode the unsigned LEB128 constant at BUF into the variable pointed to
46a2e2270fSchristos    by R, and return the number of bytes read.
47a2e2270fSchristos    If we read off the end of the buffer, zero is returned,
48a2e2270fSchristos    and nothing is stored in R.
49a2e2270fSchristos 
50a2e2270fSchristos    Note: The result is an int instead of a pointer to the next byte to be
51a2e2270fSchristos    read to avoid const-vs-non-const problems.  */
52a2e2270fSchristos 
53a2e2270fSchristos static inline size_t
54a2e2270fSchristos read_uleb128_to_uint64 (const unsigned char *buf, const unsigned char *buf_end,
55a2e2270fSchristos 			uint64_t *r)
56a2e2270fSchristos {
57a2e2270fSchristos   const unsigned char *p = buf;
58a2e2270fSchristos   unsigned int shift = 0;
59a2e2270fSchristos   uint64_t result = 0;
60a2e2270fSchristos   unsigned char byte;
61a2e2270fSchristos 
62a2e2270fSchristos   while (1)
63a2e2270fSchristos     {
64a2e2270fSchristos       if (p >= buf_end)
65a2e2270fSchristos 	return 0;
66a2e2270fSchristos 
67a2e2270fSchristos       byte = *p++;
68a2e2270fSchristos       result |= ((uint64_t) (byte & 0x7f)) << shift;
69a2e2270fSchristos       if ((byte & 0x80) == 0)
70a2e2270fSchristos 	break;
71a2e2270fSchristos       shift += 7;
72a2e2270fSchristos     }
73a2e2270fSchristos 
74a2e2270fSchristos   *r = result;
75a2e2270fSchristos   return p - buf;
76a2e2270fSchristos }
77a2e2270fSchristos 
78a2e2270fSchristos /* Decode the signed LEB128 constant at BUF into the variable pointed to
79a2e2270fSchristos    by R, and return the number of bytes read.
80a2e2270fSchristos    If we read off the end of the buffer, zero is returned,
81a2e2270fSchristos    and nothing is stored in R.
82a2e2270fSchristos 
83a2e2270fSchristos    Note: The result is an int instead of a pointer to the next byte to be
84a2e2270fSchristos    read to avoid const-vs-non-const problems.  */
85a2e2270fSchristos 
86a2e2270fSchristos static inline size_t
87a2e2270fSchristos read_sleb128_to_int64 (const unsigned char *buf, const unsigned char *buf_end,
88a2e2270fSchristos 		       int64_t *r)
89a2e2270fSchristos {
90a2e2270fSchristos   const unsigned char *p = buf;
91a2e2270fSchristos   unsigned int shift = 0;
92a2e2270fSchristos   int64_t result = 0;
93a2e2270fSchristos   unsigned char byte;
94a2e2270fSchristos 
95a2e2270fSchristos   while (1)
96a2e2270fSchristos     {
97a2e2270fSchristos       if (p >= buf_end)
98a2e2270fSchristos 	return 0;
99a2e2270fSchristos 
100a2e2270fSchristos       byte = *p++;
101a2e2270fSchristos       result |= ((uint64_t) (byte & 0x7f)) << shift;
102a2e2270fSchristos       shift += 7;
103a2e2270fSchristos       if ((byte & 0x80) == 0)
104a2e2270fSchristos 	break;
105a2e2270fSchristos     }
106a2e2270fSchristos   if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
107a2e2270fSchristos     result |= -(((uint64_t) 1) << shift);
108a2e2270fSchristos 
109a2e2270fSchristos   *r = result;
110a2e2270fSchristos   return p - buf;
111a2e2270fSchristos }
112a2e2270fSchristos 
113a2e2270fSchristos /* Return the number of bytes to read to skip past an LEB128 number in BUF.
114a2e2270fSchristos    If the end isn't found before reaching BUF_END, return zero.
115a2e2270fSchristos 
116a2e2270fSchristos    Note: The result is an int instead of a pointer to the next byte to be
117a2e2270fSchristos    read to avoid const-vs-non-const problems.  */
118a2e2270fSchristos 
119a2e2270fSchristos static inline size_t
120a2e2270fSchristos skip_leb128 (const unsigned char *buf, const unsigned char *buf_end)
121a2e2270fSchristos {
122a2e2270fSchristos   const unsigned char *p = buf;
123a2e2270fSchristos   unsigned char byte;
124a2e2270fSchristos 
125a2e2270fSchristos   while (1)
126a2e2270fSchristos     {
127a2e2270fSchristos       if (p == buf_end)
128a2e2270fSchristos 	return 0;
129a2e2270fSchristos 
130a2e2270fSchristos       byte = *p++;
131a2e2270fSchristos       if ((byte & 0x80) == 0)
132a2e2270fSchristos 	return p - buf;
133a2e2270fSchristos     }
134a2e2270fSchristos }
135a2e2270fSchristos 
136a2e2270fSchristos #endif /* LEB128_H */
137