packaging: update homepage url
[platform/upstream/elfutils.git] / libdw / encoded-value.h
1 /* DW_EH_PE_* support for libdw unwinder.
2    Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
3    This file is part of elfutils.
4
5    This file is free software; you can redistribute it and/or modify
6    it under the terms of either
7
8      * the GNU Lesser General Public License as published by the Free
9        Software Foundation; either version 3 of the License, or (at
10        your option) any later version
11
12    or
13
14      * the GNU General Public License as published by the Free
15        Software Foundation; either version 2 of the License, or (at
16        your option) any later version
17
18    or both in parallel, as here.
19
20    elfutils is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    General Public License for more details.
24
25    You should have received copies of the GNU General Public License and
26    the GNU Lesser General Public License along with this program.  If
27    not, see <http://www.gnu.org/licenses/>.  */
28
29 #ifndef _ENCODED_VALUE_H
30 #define _ENCODED_VALUE_H 1
31
32 #include <dwarf.h>
33 #include <stdlib.h>
34 #include "libdwP.h"
35 #include "../libelf/common.h"
36
37
38 /* Returns zero if the value is omitted, the encoding is unknown or
39    the (leb128) size cannot be determined.  */
40 static size_t __attribute__ ((unused))
41 encoded_value_size (const Elf_Data *data, const unsigned char e_ident[],
42                     uint8_t encoding, const uint8_t *p)
43 {
44   if (encoding == DW_EH_PE_omit)
45     return 0;
46
47   switch (encoding & 0x07)
48     {
49     case DW_EH_PE_udata2:
50       return 2;
51     case DW_EH_PE_udata4:
52       return 4;
53     case DW_EH_PE_udata8:
54       return 8;
55
56     case DW_EH_PE_absptr:
57       return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
58
59     case DW_EH_PE_uleb128:
60       if (p != NULL)
61         {
62           const uint8_t *end = p;
63           while (end < (uint8_t *) data->d_buf + data->d_size)
64             if (*end++ & 0x80u)
65               return end - p;
66         }
67
68     default:
69       return 0;
70     }
71 }
72
73 /* Returns zero when value was read successfully, minus one otherwise.  */
74 static inline int __attribute__ ((unused))
75 __libdw_cfi_read_address_inc (const Dwarf_CFI *cache,
76                               const unsigned char **addrp,
77                               int width, Dwarf_Addr *ret)
78 {
79   width = width ?: cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
80
81   if (cache->dbg != NULL)
82     return __libdw_read_address_inc (cache->dbg, IDX_debug_frame,
83                                      addrp, width, ret);
84
85   /* Only .debug_frame might have relocation to consider.
86      Read plain values from .eh_frame data.  */
87
88   const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
89   Dwarf eh_dbg = { .other_byte_order = MY_ELFDATA != cache->e_ident[EI_DATA] };
90
91   if (width == 4)
92     {
93       if (unlikely (*addrp + 4 > endp))
94         {
95         invalid_data:
96           __libdw_seterrno (DWARF_E_INVALID_CFI);
97           return -1;
98         }
99       *ret = read_4ubyte_unaligned_inc (&eh_dbg, *addrp);
100     }
101   else
102     {
103       if (unlikely (*addrp + 8 > endp))
104         goto invalid_data;
105       *ret = read_8ubyte_unaligned_inc (&eh_dbg, *addrp);
106     }
107   return 0;
108 }
109
110 /* Returns true on error, false otherwise. */
111 static bool __attribute__ ((unused))
112 read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding,
113                     const uint8_t **p, Dwarf_Addr *result)
114 {
115   *result = 0;
116   switch (encoding & 0x70)
117     {
118     case DW_EH_PE_absptr:
119       break;
120     case DW_EH_PE_pcrel:
121       *result = (cache->frame_vaddr
122                  + (*p - (const uint8_t *) cache->data->d.d_buf));
123       break;
124     case DW_EH_PE_textrel:
125       // ia64: segrel
126       *result = cache->textrel;
127       break;
128     case DW_EH_PE_datarel:
129       // i386: GOTOFF
130       // ia64: gprel
131       *result = cache->datarel;
132       break;
133     case DW_EH_PE_funcrel:      /* XXX */
134       break;
135     case DW_EH_PE_aligned:
136       {
137         const size_t size = encoded_value_size (&cache->data->d,
138                                                 cache->e_ident,
139                                                 encoding, *p);
140         if (unlikely (size == 0))
141           return true;
142         size_t align = ((cache->frame_vaddr
143                          + (*p - (const uint8_t *) cache->data->d.d_buf))
144                         & (size - 1));
145         if (align != 0)
146           *p += size - align;
147         break;
148       }
149
150     default:
151       __libdw_seterrno (DWARF_E_INVALID_CFI);
152       return true;
153     }
154
155   Dwarf_Addr value = 0;
156   const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
157   switch (encoding & 0x0f)
158     {
159     case DW_EH_PE_udata2:
160       if (unlikely (*p + 2 > endp))
161         {
162         invalid_data:
163           __libdw_seterrno (DWARF_E_INVALID_CFI);
164           return true;
165         }
166       value = read_2ubyte_unaligned_inc (cache, *p);
167       break;
168
169     case DW_EH_PE_sdata2:
170       if (unlikely (*p + 2 > endp))
171         goto invalid_data;
172       value = read_2sbyte_unaligned_inc (cache, *p);
173       break;
174
175     case DW_EH_PE_udata4:
176       if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
177         return true;
178       break;
179
180     case DW_EH_PE_sdata4:
181       if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
182         return true;
183       value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend.  */
184       break;
185
186     case DW_EH_PE_udata8:
187     case DW_EH_PE_sdata8:
188       if (unlikely (__libdw_cfi_read_address_inc (cache, p, 8, &value) != 0))
189         return true;
190       break;
191
192     case DW_EH_PE_absptr:
193       if (unlikely (__libdw_cfi_read_address_inc (cache, p, 0, &value) != 0))
194         return true;
195       break;
196
197     case DW_EH_PE_uleb128:
198       get_uleb128 (value, *p, endp);
199       break;
200
201     case DW_EH_PE_sleb128:
202       get_sleb128 (value, *p, endp);
203       break;
204
205     default:
206       __libdw_seterrno (DWARF_E_INVALID_CFI);
207       return true;
208     }
209
210   *result += value;
211
212   if (encoding & DW_EH_PE_indirect)
213     {
214       if (unlikely (*result < cache->frame_vaddr))
215         return true;
216       *result -= cache->frame_vaddr;
217       size_t ptrsize = encoded_value_size (NULL, cache->e_ident,
218                                            DW_EH_PE_absptr, NULL);
219       if (unlikely (cache->data->d.d_size < ptrsize
220                     || *result > (cache->data->d.d_size - ptrsize)))
221         return true;
222       const uint8_t *ptr = cache->data->d.d_buf + *result;
223       if (unlikely (__libdw_cfi_read_address_inc (cache, &ptr, 0, result)
224                     != 0))
225         return true;
226     }
227
228   return false;
229 }
230
231 #endif  /* encoded-value.h */