Brian Silverman | 8649792 | 2018-02-10 19:28:39 -0500 | [diff] [blame^] | 1 | /* Advance to next CFI entry. |
| 2 | Copyright (C) 2009-2010, 2014 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 | #ifdef HAVE_CONFIG_H |
| 30 | # include <config.h> |
| 31 | #endif |
| 32 | |
| 33 | #include "cfi.h" |
| 34 | #include "encoded-value.h" |
| 35 | |
| 36 | #include <string.h> |
| 37 | |
| 38 | |
| 39 | int |
| 40 | dwarf_next_cfi (const unsigned char e_ident[], |
| 41 | Elf_Data *data, |
| 42 | bool eh_frame_p, |
| 43 | Dwarf_Off off, |
| 44 | Dwarf_Off *next_off, |
| 45 | Dwarf_CFI_Entry *entry) |
| 46 | { |
| 47 | /* Dummy struct for memory-access.h macros. */ |
| 48 | BYTE_ORDER_DUMMY (dw, e_ident); |
| 49 | |
| 50 | /* If we reached the end before don't do anything. */ |
| 51 | if (off == (Dwarf_Off) -1l |
| 52 | /* Make sure there is enough space in the .debug_frame section |
| 53 | for at least the initial word. We cannot test the rest since |
| 54 | we don't know yet whether this is a 64-bit object or not. */ |
| 55 | || unlikely (off + 4 >= data->d_size)) |
| 56 | { |
| 57 | *next_off = (Dwarf_Off) -1l; |
| 58 | return 1; |
| 59 | } |
| 60 | |
| 61 | /* This points into the .debug_frame section at the start of the entry. */ |
| 62 | const uint8_t *bytes = data->d_buf + off; |
| 63 | const uint8_t *limit = data->d_buf + data->d_size; |
| 64 | |
| 65 | /* The format of a CFI entry is described in DWARF3 6.4.1: |
| 66 | */ |
| 67 | |
| 68 | uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes); |
| 69 | size_t offset_size = 4; |
| 70 | if (length == DWARF3_LENGTH_64_BIT) |
| 71 | { |
| 72 | /* This is the 64-bit DWARF format. */ |
| 73 | offset_size = 8; |
| 74 | if (unlikely (limit - bytes < 8)) |
| 75 | { |
| 76 | invalid: |
| 77 | __libdw_seterrno (DWARF_E_INVALID_DWARF); |
| 78 | return -1; |
| 79 | } |
| 80 | length = read_8ubyte_unaligned_inc (&dw, bytes); |
| 81 | } |
| 82 | if (unlikely ((uint64_t) (limit - bytes) < length) |
| 83 | || unlikely (length < offset_size + 1)) |
| 84 | goto invalid; |
| 85 | |
| 86 | /* Now we know how large the entry is. Note the trick in the |
| 87 | computation. If the offset_size is 4 the '- 4' term undoes the |
| 88 | '2 *'. If offset_size is 8 this term computes the size of the |
| 89 | escape value plus the 8 byte offset. */ |
| 90 | *next_off = off + (2 * offset_size - 4) + length; |
| 91 | |
| 92 | limit = bytes + length; |
| 93 | |
| 94 | const uint8_t *const cie_pointer_start = bytes; |
| 95 | if (offset_size == 8) |
| 96 | entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes); |
| 97 | else |
| 98 | { |
| 99 | entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes); |
| 100 | /* Canonicalize the 32-bit CIE_ID value to 64 bits. */ |
| 101 | if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32) |
| 102 | entry->cie.CIE_id = DW_CIE_ID_64; |
| 103 | } |
| 104 | if (eh_frame_p) |
| 105 | { |
| 106 | /* Canonicalize the .eh_frame CIE pointer to .debug_frame format. */ |
| 107 | if (entry->cie.CIE_id == 0) |
| 108 | entry->cie.CIE_id = DW_CIE_ID_64; |
| 109 | else |
| 110 | { |
| 111 | /* In .eh_frame format, a CIE pointer is the distance from where |
| 112 | it appears back to the beginning of the CIE. */ |
| 113 | ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf; |
| 114 | if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos) |
| 115 | || unlikely (pos <= (ptrdiff_t) offset_size)) |
| 116 | goto invalid; |
| 117 | entry->cie.CIE_id = pos - entry->cie.CIE_id; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | if (entry->cie.CIE_id == DW_CIE_ID_64) |
| 122 | { |
| 123 | /* Read the version stamp. Always an 8-bit value. */ |
| 124 | uint8_t version = *bytes++; |
| 125 | |
| 126 | if (version != 1 && (unlikely (version < 3) || unlikely (version > 4))) |
| 127 | goto invalid; |
| 128 | |
| 129 | entry->cie.augmentation = (const char *) bytes; |
| 130 | |
| 131 | bytes = memchr (bytes, '\0', limit - bytes); |
| 132 | if (unlikely (bytes == NULL)) |
| 133 | goto invalid; |
| 134 | ++bytes; |
| 135 | |
| 136 | /* The address size for CFI is implicit in the ELF class. */ |
| 137 | uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; |
| 138 | uint_fast8_t segment_size = 0; |
| 139 | if (version >= 4) |
| 140 | { |
| 141 | if (unlikely (limit - bytes < 5)) |
| 142 | goto invalid; |
| 143 | /* XXX We don't actually support address_size not matching the class. |
| 144 | To do so, we'd have to return it here so that intern_new_cie |
| 145 | could use it choose a specific fde_encoding. */ |
| 146 | if (unlikely (*bytes != address_size)) |
| 147 | { |
| 148 | __libdw_seterrno (DWARF_E_VERSION); |
| 149 | return -1; |
| 150 | } |
| 151 | address_size = *bytes++; |
| 152 | segment_size = *bytes++; |
| 153 | /* We don't actually support segment selectors. We'd have to |
| 154 | roll this into the fde_encoding bits or something. */ |
| 155 | if (unlikely (segment_size != 0)) |
| 156 | { |
| 157 | __libdw_seterrno (DWARF_E_VERSION); |
| 158 | return -1; |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | const char *ap = entry->cie.augmentation; |
| 163 | |
| 164 | /* g++ v2 "eh" has pointer immediately following augmentation string, |
| 165 | so it must be handled first. */ |
| 166 | if (unlikely (ap[0] == 'e' && ap[1] == 'h')) |
| 167 | { |
| 168 | ap += 2; |
| 169 | bytes += address_size; |
| 170 | } |
| 171 | |
| 172 | if (bytes >= limit) |
| 173 | goto invalid; |
| 174 | get_uleb128 (entry->cie.code_alignment_factor, bytes, limit); |
| 175 | |
| 176 | if (bytes >= limit) |
| 177 | goto invalid; |
| 178 | get_sleb128 (entry->cie.data_alignment_factor, bytes, limit); |
| 179 | |
| 180 | if (bytes >= limit) |
| 181 | goto invalid; |
| 182 | |
| 183 | if (version >= 3) /* DWARF 3+ */ |
| 184 | get_uleb128 (entry->cie.return_address_register, bytes, limit); |
| 185 | else /* DWARF 2 */ |
| 186 | entry->cie.return_address_register = *bytes++; |
| 187 | |
| 188 | /* If we have sized augmentation data, |
| 189 | we don't need to grok it all. */ |
| 190 | entry->cie.fde_augmentation_data_size = 0; |
| 191 | bool sized_augmentation = *ap == 'z'; |
| 192 | if (sized_augmentation) |
| 193 | { |
| 194 | if (bytes >= limit) |
| 195 | goto invalid; |
| 196 | get_uleb128 (entry->cie.augmentation_data_size, bytes, limit); |
| 197 | if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size) |
| 198 | goto invalid; |
| 199 | entry->cie.augmentation_data = bytes; |
| 200 | bytes += entry->cie.augmentation_data_size; |
| 201 | } |
| 202 | else |
| 203 | { |
| 204 | entry->cie.augmentation_data = bytes; |
| 205 | |
| 206 | for (; *ap != '\0'; ++ap) |
| 207 | { |
| 208 | uint8_t encoding; |
| 209 | switch (*ap) |
| 210 | { |
| 211 | case 'L': /* Skip LSDA pointer encoding byte. */ |
| 212 | case 'R': /* Skip FDE address encoding byte. */ |
| 213 | encoding = *bytes++; |
| 214 | entry->cie.fde_augmentation_data_size |
| 215 | += encoded_value_size (data, e_ident, encoding, NULL); |
| 216 | continue; |
| 217 | case 'P': /* Skip encoded personality routine pointer. */ |
| 218 | encoding = *bytes++; |
| 219 | bytes += encoded_value_size (data, e_ident, encoding, bytes); |
| 220 | continue; |
| 221 | case 'S': /* Skip signal-frame flag. */ |
| 222 | continue; |
| 223 | default: |
| 224 | /* Unknown augmentation string. initial_instructions might |
| 225 | actually start with some augmentation data. */ |
| 226 | break; |
| 227 | } |
| 228 | break; |
| 229 | } |
| 230 | entry->cie.augmentation_data_size |
| 231 | = bytes - entry->cie.augmentation_data; |
| 232 | } |
| 233 | |
| 234 | entry->cie.initial_instructions = bytes; |
| 235 | entry->cie.initial_instructions_end = limit; |
| 236 | } |
| 237 | else |
| 238 | { |
| 239 | entry->fde.start = bytes; |
| 240 | entry->fde.end = limit; |
| 241 | } |
| 242 | |
| 243 | return 0; |
| 244 | } |
| 245 | INTDEF (dwarf_next_cfi) |