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