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