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.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
29 #ifndef _ENCODED_VALUE_H
30 #define _ENCODED_VALUE_H 1
35 #include "../libelf/common.h"
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)
44 if (encoding == DW_EH_PE_omit)
47 switch (encoding & 0x07)
57 return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
59 case DW_EH_PE_uleb128:
62 const uint8_t *end = p;
63 while (end < (uint8_t *) data->d_buf + data->d_size)
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)
79 width = width ?: cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
81 if (cache->dbg != NULL)
82 return __libdw_read_address_inc (cache->dbg, IDX_debug_frame,
85 /* Only .debug_frame might have relocation to consider.
86 Read plain values from .eh_frame data. */
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] };
93 if (unlikely (*addrp + 4 > endp))
96 __libdw_seterrno (DWARF_E_INVALID_CFI);
99 *ret = read_4ubyte_unaligned_inc (&eh_dbg, *addrp);
103 if (unlikely (*addrp + 8 > endp))
105 *ret = read_8ubyte_unaligned_inc (&eh_dbg, *addrp);
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)
116 switch (encoding & 0x70)
118 case DW_EH_PE_absptr:
121 *result = (cache->frame_vaddr
122 + (*p - (const uint8_t *) cache->data->d.d_buf));
124 case DW_EH_PE_textrel:
126 *result = cache->textrel;
128 case DW_EH_PE_datarel:
131 *result = cache->datarel;
133 case DW_EH_PE_funcrel: /* XXX */
135 case DW_EH_PE_aligned:
137 const size_t size = encoded_value_size (&cache->data->d,
140 if (unlikely (size == 0))
142 size_t align = ((cache->frame_vaddr
143 + (*p - (const uint8_t *) cache->data->d.d_buf))
151 __libdw_seterrno (DWARF_E_INVALID_CFI);
155 Dwarf_Addr value = 0;
156 const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
157 switch (encoding & 0x0f)
159 case DW_EH_PE_udata2:
160 if (unlikely (*p + 2 > endp))
163 __libdw_seterrno (DWARF_E_INVALID_CFI);
166 value = read_2ubyte_unaligned_inc (cache, *p);
169 case DW_EH_PE_sdata2:
170 if (unlikely (*p + 2 > endp))
172 value = read_2sbyte_unaligned_inc (cache, *p);
175 case DW_EH_PE_udata4:
176 if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
180 case DW_EH_PE_sdata4:
181 if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
183 value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend. */
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))
192 case DW_EH_PE_absptr:
193 if (unlikely (__libdw_cfi_read_address_inc (cache, p, 0, &value) != 0))
197 case DW_EH_PE_uleb128:
198 get_uleb128 (value, *p, endp);
201 case DW_EH_PE_sleb128:
202 get_sleb128 (value, *p, endp);
206 __libdw_seterrno (DWARF_E_INVALID_CFI);
212 if (encoding & DW_EH_PE_indirect)
214 if (unlikely (*result < cache->frame_vaddr))
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)))
222 const uint8_t *ptr = cache->data->d.d_buf + *result;
223 if (unlikely (__libdw_cfi_read_address_inc (cache, &ptr, 0, result)
231 #endif /* encoded-value.h */