Branch data Line data Source code
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 "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 : 13736 : encoded_value_size (const Elf_Data *data, const unsigned char e_ident[],
42 : : uint8_t encoding, const uint8_t *p)
43 : : {
44 [ - + ]: 13736 : if (encoding == DW_EH_PE_omit)
45 : : return 0;
46 : :
47 [ - + + - : 13736 : 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 : 88 : case DW_EH_PE_absptr:
57 [ + + ]: 88 : return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
58 : :
59 : 0 : case DW_EH_PE_uleb128:
60 [ # # ]: 0 : if (p != NULL)
61 : : {
62 : : const uint8_t *end = p;
63 [ # # ]: 0 : while (end < (uint8_t *) data->d_buf + data->d_size)
64 [ # # ]: 0 : if (*end++ & 0x80u)
65 : 0 : return end - p;
66 : : }
67 : : return 0;
68 : :
69 : : default:
70 : : return 0;
71 : : }
72 : : }
73 : :
74 : : /* Returns zero when value was read successfully, minus one otherwise. */
75 : : static inline int __attribute__ ((unused))
76 : 350810 : __libdw_cfi_read_address_inc (const Dwarf_CFI *cache,
77 : : const unsigned char **addrp,
78 : : int width, Dwarf_Addr *ret)
79 : : {
80 [ - + - - ]: 350810 : width = width ?: cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
81 : :
82 [ + + ]: 350810 : if (cache->dbg != NULL)
83 : 384 : return __libdw_read_address_inc (cache->dbg, IDX_debug_frame,
84 : : addrp, width, ret);
85 : :
86 : : /* Only .debug_frame might have relocation to consider.
87 : : Read plain values from .eh_frame data. */
88 : :
89 : 350426 : const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
90 : 350426 : Dwarf eh_dbg = { .other_byte_order = MY_ELFDATA != cache->e_ident[EI_DATA] };
91 : :
92 [ + - ]: 350426 : if (width == 4)
93 : : {
94 [ - + ]: 350426 : if (unlikely (*addrp + 4 > endp))
95 : : {
96 : 0 : invalid_data:
97 : 0 : __libdw_seterrno (DWARF_E_INVALID_CFI);
98 : 0 : return -1;
99 : : }
100 [ + + ]: 350426 : *ret = read_4ubyte_unaligned_inc (&eh_dbg, *addrp);
101 : : }
102 : : else
103 : : {
104 [ # # ]: 0 : if (unlikely (*addrp + 8 > endp))
105 : 0 : goto invalid_data;
106 [ # # ]: 0 : *ret = read_8ubyte_unaligned_inc (&eh_dbg, *addrp);
107 : : }
108 : : return 0;
109 : : }
110 : :
111 : : /* Returns true on error, false otherwise. */
112 : : static bool __attribute__ ((unused))
113 : 350810 : read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding,
114 : : const uint8_t **p, Dwarf_Addr *result)
115 : : {
116 : 350810 : *result = 0;
117 [ + - + - : 350810 : switch (encoding & 0x70)
- + ]
118 : : {
119 : : case DW_EH_PE_absptr:
120 : : break;
121 : 38950 : case DW_EH_PE_pcrel:
122 : 38950 : *result = (cache->frame_vaddr
123 : 38950 : + (*p - (const uint8_t *) cache->data->d.d_buf));
124 : 38950 : break;
125 : 0 : case DW_EH_PE_textrel:
126 : : // ia64: segrel
127 : 0 : *result = cache->textrel;
128 : 0 : break;
129 : 272506 : case DW_EH_PE_datarel:
130 : : // i386: GOTOFF
131 : : // ia64: gprel
132 : 272506 : *result = cache->datarel;
133 : 272506 : break;
134 : : case DW_EH_PE_funcrel: /* XXX */
135 : : break;
136 : 0 : case DW_EH_PE_aligned:
137 : : {
138 : 0 : const size_t size = encoded_value_size (&cache->data->d,
139 : 0 : cache->e_ident,
140 : : encoding, *p);
141 [ # # ]: 0 : if (unlikely (size == 0))
142 : : return true;
143 : 0 : size_t align = ((cache->frame_vaddr
144 : 0 : + (*p - (const uint8_t *) cache->data->d.d_buf))
145 : 0 : & (size - 1));
146 [ # # ]: 0 : if (align != 0)
147 : 0 : *p += size - align;
148 : : break;
149 : : }
150 : :
151 : 0 : default:
152 : 0 : __libdw_seterrno (DWARF_E_INVALID_CFI);
153 : 0 : return true;
154 : : }
155 : :
156 : 350810 : Dwarf_Addr value = 0;
157 : 350810 : const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
158 [ - - + + : 350810 : switch (encoding & 0x0f)
+ - - -
- ]
159 : : {
160 : 0 : case DW_EH_PE_udata2:
161 [ # # ]: 0 : if (unlikely (*p + 2 > endp))
162 : : {
163 : 0 : invalid_data:
164 : 0 : __libdw_seterrno (DWARF_E_INVALID_CFI);
165 : 0 : return true;
166 : : }
167 [ # # ]: 0 : value = read_2ubyte_unaligned_inc (cache, *p);
168 : 0 : break;
169 : :
170 : 0 : case DW_EH_PE_sdata2:
171 [ # # ]: 0 : if (unlikely (*p + 2 > endp))
172 : 0 : goto invalid_data;
173 [ # # ]: 0 : value = read_2sbyte_unaligned_inc (cache, *p);
174 : 0 : break;
175 : :
176 : 228 : case DW_EH_PE_udata4:
177 [ - + ]: 228 : if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
178 : : return true;
179 : : break;
180 : :
181 : 350290 : case DW_EH_PE_sdata4:
182 [ - + ]: 350290 : if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
183 : : return true;
184 : 350290 : value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend. */
185 : 350290 : break;
186 : :
187 : 292 : case DW_EH_PE_udata8:
188 : : case DW_EH_PE_sdata8:
189 [ - + ]: 292 : if (unlikely (__libdw_cfi_read_address_inc (cache, p, 8, &value) != 0))
190 : : return true;
191 : : break;
192 : :
193 : 0 : case DW_EH_PE_absptr:
194 [ # # ]: 0 : if (unlikely (__libdw_cfi_read_address_inc (cache, p, 0, &value) != 0))
195 : : return true;
196 : : break;
197 : :
198 : 0 : case DW_EH_PE_uleb128:
199 [ # # ]: 0 : if (*p >= endp)
200 : 0 : goto invalid_data;
201 : 0 : get_uleb128 (value, *p, endp);
202 : 0 : break;
203 : :
204 : 0 : case DW_EH_PE_sleb128:
205 [ # # ]: 0 : if (*p >= endp)
206 : 0 : goto invalid_data;
207 : 0 : get_sleb128 (value, *p, endp);
208 : 0 : break;
209 : :
210 : 0 : default:
211 : 0 : __libdw_seterrno (DWARF_E_INVALID_CFI);
212 : 0 : return true;
213 : : }
214 : :
215 : 350810 : *result += value;
216 : :
217 [ - + ]: 350810 : if (encoding & DW_EH_PE_indirect)
218 : : {
219 [ # # ]: 0 : if (unlikely (*result < cache->frame_vaddr))
220 : 0 : return true;
221 : 0 : *result -= cache->frame_vaddr;
222 [ # # ]: 0 : size_t ptrsize = encoded_value_size (NULL, cache->e_ident,
223 : : DW_EH_PE_absptr, NULL);
224 [ # # # # ]: 0 : if (unlikely (cache->data->d.d_size < ptrsize
225 : : || *result > (cache->data->d.d_size - ptrsize)))
226 : : return true;
227 : 0 : const uint8_t *ptr = cache->data->d.d_buf + *result;
228 [ # # ]: 0 : if (unlikely (__libdw_cfi_read_address_inc (cache, &ptr, 0, result)
229 : : != 0))
230 : : return true;
231 : : }
232 : :
233 : : return false;
234 : : }
235 : :
236 : : #endif /* encoded-value.h */
|