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 */ 232