/src/elfutils/libdw/encoded-value.h
Line | Count | Source (jump to first uncovered line) |
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 | | encoded_value_size (const Elf_Data *data, const unsigned char e_ident[], |
42 | | uint8_t encoding, const uint8_t *p) |
43 | 0 | { |
44 | 0 | if (encoding == DW_EH_PE_omit) |
45 | 0 | return 0; |
46 | | |
47 | 0 | switch (encoding & 0x07) |
48 | 0 | { |
49 | 0 | case DW_EH_PE_udata2: |
50 | 0 | return 2; |
51 | 0 | case DW_EH_PE_udata4: |
52 | 0 | return 4; |
53 | 0 | case DW_EH_PE_udata8: |
54 | 0 | return 8; |
55 | | |
56 | 0 | case DW_EH_PE_absptr: |
57 | 0 | return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; |
58 | | |
59 | 0 | case DW_EH_PE_uleb128: |
60 | 0 | if (p != NULL) |
61 | 0 | { |
62 | 0 | 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 | 0 | } |
67 | 0 | return 0; |
68 | | |
69 | 0 | default: |
70 | 0 | return 0; |
71 | 0 | } |
72 | 0 | } Unexecuted instantiation: fde.c:encoded_value_size Unexecuted instantiation: cfi.c:encoded_value_size Unexecuted instantiation: dwarf_getcfi_elf.c:encoded_value_size Unexecuted instantiation: dwarf_next_cfi.c:encoded_value_size Unexecuted instantiation: cie.c:encoded_value_size |
73 | | |
74 | | /* Returns zero when value was read successfully, minus one otherwise. */ |
75 | | static inline int __attribute__ ((unused)) |
76 | | __libdw_cfi_read_address_inc (const Dwarf_CFI *cache, |
77 | | const unsigned char **addrp, |
78 | | int width, Dwarf_Addr *ret) |
79 | 0 | { |
80 | 0 | width = width ?: cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; |
81 | |
|
82 | 0 | if (cache->dbg != NULL) |
83 | 0 | return __libdw_read_address_inc (cache->dbg, IDX_debug_frame, |
84 | 0 | addrp, width, ret); |
85 | | |
86 | | /* Only .debug_frame might have relocation to consider. |
87 | | Read plain values from .eh_frame data. */ |
88 | | |
89 | 0 | const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size; |
90 | 0 | Dwarf eh_dbg = { .other_byte_order = MY_ELFDATA != cache->e_ident[EI_DATA] }; |
91 | |
|
92 | 0 | if (width == 4) |
93 | 0 | { |
94 | 0 | if (unlikely (*addrp + 4 > endp)) |
95 | 0 | { |
96 | 0 | invalid_data: |
97 | 0 | __libdw_seterrno (DWARF_E_INVALID_CFI); |
98 | 0 | return -1; |
99 | 0 | } |
100 | 0 | *ret = read_4ubyte_unaligned_inc (&eh_dbg, *addrp); |
101 | 0 | } |
102 | 0 | else |
103 | 0 | { |
104 | 0 | if (unlikely (*addrp + 8 > endp)) |
105 | 0 | goto invalid_data; |
106 | 0 | *ret = read_8ubyte_unaligned_inc (&eh_dbg, *addrp); |
107 | 0 | } |
108 | 0 | return 0; |
109 | 0 | } Unexecuted instantiation: fde.c:__libdw_cfi_read_address_inc Unexecuted instantiation: cfi.c:__libdw_cfi_read_address_inc Unexecuted instantiation: dwarf_getcfi_elf.c:__libdw_cfi_read_address_inc Unexecuted instantiation: dwarf_next_cfi.c:__libdw_cfi_read_address_inc Unexecuted instantiation: cie.c:__libdw_cfi_read_address_inc |
110 | | |
111 | | /* Returns true on error, false otherwise. */ |
112 | | static bool __attribute__ ((unused)) |
113 | | read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, |
114 | | const uint8_t **p, Dwarf_Addr *result) |
115 | 0 | { |
116 | 0 | *result = 0; |
117 | 0 | switch (encoding & 0x70) |
118 | 0 | { |
119 | 0 | case DW_EH_PE_absptr: |
120 | 0 | break; |
121 | 0 | case DW_EH_PE_pcrel: |
122 | 0 | *result = (cache->frame_vaddr |
123 | 0 | + (*p - (const uint8_t *) cache->data->d.d_buf)); |
124 | 0 | break; |
125 | 0 | case DW_EH_PE_textrel: |
126 | | // ia64: segrel |
127 | 0 | *result = cache->textrel; |
128 | 0 | break; |
129 | 0 | case DW_EH_PE_datarel: |
130 | | // i386: GOTOFF |
131 | | // ia64: gprel |
132 | 0 | *result = cache->datarel; |
133 | 0 | break; |
134 | 0 | case DW_EH_PE_funcrel: /* XXX */ |
135 | 0 | break; |
136 | 0 | case DW_EH_PE_aligned: |
137 | 0 | { |
138 | 0 | const size_t size = encoded_value_size (&cache->data->d, |
139 | 0 | cache->e_ident, |
140 | 0 | encoding, *p); |
141 | 0 | if (unlikely (size == 0)) |
142 | 0 | 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 | 0 | break; |
149 | 0 | } |
150 | | |
151 | 0 | default: |
152 | 0 | __libdw_seterrno (DWARF_E_INVALID_CFI); |
153 | 0 | return true; |
154 | 0 | } |
155 | | |
156 | 0 | Dwarf_Addr value = 0; |
157 | 0 | const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size; |
158 | 0 | switch (encoding & 0x0f) |
159 | 0 | { |
160 | 0 | case DW_EH_PE_udata2: |
161 | 0 | if (unlikely (*p + 2 > endp)) |
162 | 0 | { |
163 | 0 | invalid_data: |
164 | 0 | __libdw_seterrno (DWARF_E_INVALID_CFI); |
165 | 0 | return true; |
166 | 0 | } |
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 | 0 | case DW_EH_PE_udata4: |
177 | 0 | if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0)) |
178 | 0 | return true; |
179 | 0 | break; |
180 | | |
181 | 0 | case DW_EH_PE_sdata4: |
182 | 0 | if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0)) |
183 | 0 | return true; |
184 | 0 | value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend. */ |
185 | 0 | break; |
186 | | |
187 | 0 | case DW_EH_PE_udata8: |
188 | 0 | case DW_EH_PE_sdata8: |
189 | 0 | if (unlikely (__libdw_cfi_read_address_inc (cache, p, 8, &value) != 0)) |
190 | 0 | return true; |
191 | 0 | break; |
192 | | |
193 | 0 | case DW_EH_PE_absptr: |
194 | 0 | if (unlikely (__libdw_cfi_read_address_inc (cache, p, 0, &value) != 0)) |
195 | 0 | return true; |
196 | 0 | 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 | 0 | } |
214 | | |
215 | 0 | *result += value; |
216 | |
|
217 | 0 | if (encoding & DW_EH_PE_indirect) |
218 | 0 | { |
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 | 0 | DW_EH_PE_absptr, NULL); |
224 | 0 | if (unlikely (cache->data->d.d_size < ptrsize |
225 | 0 | || *result > (cache->data->d.d_size - ptrsize))) |
226 | 0 | 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 | != 0)) |
230 | 0 | return true; |
231 | 0 | } |
232 | | |
233 | 0 | return false; |
234 | 0 | } Unexecuted instantiation: fde.c:read_encoded_value Unexecuted instantiation: cfi.c:read_encoded_value Unexecuted instantiation: dwarf_getcfi_elf.c:read_encoded_value Unexecuted instantiation: dwarf_next_cfi.c:read_encoded_value Unexecuted instantiation: cie.c:read_encoded_value |
235 | | |
236 | | #endif /* encoded-value.h */ |