| /* Advance to next CFI entry. |
| Copyright (C) 2009-2010 Red Hat, Inc. |
| This file is part of elfutils. |
| |
| This file is free software; you can redistribute it and/or modify |
| it under the terms of either |
| |
| * the GNU Lesser General Public License as published by the Free |
| Software Foundation; either version 3 of the License, or (at |
| your option) any later version |
| |
| or |
| |
| * the GNU General Public License as published by the Free |
| Software Foundation; either version 2 of the License, or (at |
| your option) any later version |
| |
| or both in parallel, as here. |
| |
| elfutils is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received copies of the GNU General Public License and |
| the GNU Lesser General Public License along with this program. If |
| not, see <http://www.gnu.org/licenses/>. */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif |
| |
| #include "cfi.h" |
| #include "encoded-value.h" |
| |
| #include <string.h> |
| |
| |
| int |
| dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry) |
| const unsigned char e_ident[]; |
| Elf_Data *data; |
| bool eh_frame_p; |
| Dwarf_Off off; |
| Dwarf_Off *next_off; |
| Dwarf_CFI_Entry *entry; |
| { |
| /* Dummy struct for memory-access.h macros. */ |
| BYTE_ORDER_DUMMY (dw, e_ident); |
| |
| /* If we reached the end before don't do anything. */ |
| if (off == (Dwarf_Off) -1l |
| /* Make sure there is enough space in the .debug_frame section |
| for at least the initial word. We cannot test the rest since |
| we don't know yet whether this is a 64-bit object or not. */ |
| || unlikely (off + 4 >= data->d_size)) |
| { |
| *next_off = (Dwarf_Off) -1l; |
| return 1; |
| } |
| |
| /* This points into the .debug_frame section at the start of the entry. */ |
| const uint8_t *bytes = data->d_buf + off; |
| const uint8_t *limit = data->d_buf + data->d_size; |
| |
| /* The format of a CFI entry is described in DWARF3 6.4.1: |
| */ |
| |
| uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes); |
| size_t offset_size = 4; |
| if (length == DWARF3_LENGTH_64_BIT) |
| { |
| /* This is the 64-bit DWARF format. */ |
| offset_size = 8; |
| if (unlikely (limit - bytes < 8)) |
| { |
| invalid: |
| __libdw_seterrno (DWARF_E_INVALID_DWARF); |
| return -1; |
| } |
| length = read_8ubyte_unaligned_inc (&dw, bytes); |
| } |
| if (unlikely ((uint64_t) (limit - bytes) < length) |
| || unlikely (length < offset_size + 1)) |
| goto invalid; |
| |
| /* Now we know how large the entry is. Note the trick in the |
| computation. If the offset_size is 4 the '- 4' term undoes the |
| '2 *'. If offset_size is 8 this term computes the size of the |
| escape value plus the 8 byte offset. */ |
| *next_off = off + (2 * offset_size - 4) + length; |
| |
| limit = bytes + length; |
| |
| const uint8_t *const cie_pointer_start = bytes; |
| if (offset_size == 8) |
| entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes); |
| else |
| { |
| entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes); |
| /* Canonicalize the 32-bit CIE_ID value to 64 bits. */ |
| if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32) |
| entry->cie.CIE_id = DW_CIE_ID_64; |
| } |
| if (eh_frame_p) |
| { |
| /* Canonicalize the .eh_frame CIE pointer to .debug_frame format. */ |
| if (entry->cie.CIE_id == 0) |
| entry->cie.CIE_id = DW_CIE_ID_64; |
| else |
| { |
| /* In .eh_frame format, a CIE pointer is the distance from where |
| it appears back to the beginning of the CIE. */ |
| ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf; |
| if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos) |
| || unlikely (pos <= (ptrdiff_t) offset_size)) |
| goto invalid; |
| entry->cie.CIE_id = pos - entry->cie.CIE_id; |
| } |
| } |
| |
| if (entry->cie.CIE_id == DW_CIE_ID_64) |
| { |
| /* Read the version stamp. Always an 8-bit value. */ |
| uint8_t version = *bytes++; |
| |
| if (version != 1 && (unlikely (version < 3) || unlikely (version > 4))) |
| goto invalid; |
| |
| entry->cie.augmentation = (const char *) bytes; |
| |
| bytes = memchr (bytes, '\0', limit - bytes); |
| if (unlikely (bytes == NULL)) |
| goto invalid; |
| ++bytes; |
| |
| /* The address size for CFI is implicit in the ELF class. */ |
| uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; |
| uint_fast8_t segment_size = 0; |
| if (version >= 4) |
| { |
| if (unlikely (limit - bytes < 5)) |
| goto invalid; |
| /* XXX We don't actually support address_size not matching the class. |
| To do so, we'd have to return it here so that intern_new_cie |
| could use it choose a specific fde_encoding. */ |
| if (unlikely (*bytes != address_size)) |
| { |
| __libdw_seterrno (DWARF_E_VERSION); |
| return -1; |
| } |
| address_size = *bytes++; |
| segment_size = *bytes++; |
| /* We don't actually support segment selectors. We'd have to |
| roll this into the fde_encoding bits or something. */ |
| if (unlikely (segment_size != 0)) |
| { |
| __libdw_seterrno (DWARF_E_VERSION); |
| return -1; |
| } |
| } |
| |
| const char *ap = entry->cie.augmentation; |
| |
| /* g++ v2 "eh" has pointer immediately following augmentation string, |
| so it must be handled first. */ |
| if (unlikely (ap[0] == 'e' && ap[1] == 'h')) |
| { |
| ap += 2; |
| bytes += address_size; |
| } |
| |
| get_uleb128 (entry->cie.code_alignment_factor, bytes); |
| get_sleb128 (entry->cie.data_alignment_factor, bytes); |
| |
| if (version >= 3) /* DWARF 3+ */ |
| get_uleb128 (entry->cie.return_address_register, bytes); |
| else /* DWARF 2 */ |
| entry->cie.return_address_register = *bytes++; |
| |
| /* If we have sized augmentation data, |
| we don't need to grok it all. */ |
| entry->cie.fde_augmentation_data_size = 0; |
| bool sized_augmentation = *ap == 'z'; |
| if (sized_augmentation) |
| { |
| get_uleb128 (entry->cie.augmentation_data_size, bytes); |
| if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size) |
| goto invalid; |
| entry->cie.augmentation_data = bytes; |
| bytes += entry->cie.augmentation_data_size; |
| } |
| else |
| { |
| entry->cie.augmentation_data = bytes; |
| |
| for (; *ap != '\0'; ++ap) |
| { |
| uint8_t encoding; |
| switch (*ap) |
| { |
| case 'L': /* Skip LSDA pointer encoding byte. */ |
| case 'R': /* Skip FDE address encoding byte. */ |
| encoding = *bytes++; |
| entry->cie.fde_augmentation_data_size |
| += encoded_value_size (data, e_ident, encoding, NULL); |
| continue; |
| case 'P': /* Skip encoded personality routine pointer. */ |
| encoding = *bytes++; |
| bytes += encoded_value_size (data, e_ident, encoding, bytes); |
| continue; |
| case 'S': /* Skip signal-frame flag. */ |
| continue; |
| default: |
| /* Unknown augmentation string. initial_instructions might |
| actually start with some augmentation data. */ |
| break; |
| } |
| break; |
| } |
| entry->cie.augmentation_data_size |
| = bytes - entry->cie.augmentation_data; |
| } |
| |
| entry->cie.initial_instructions = bytes; |
| entry->cie.initial_instructions_end = limit; |
| } |
| else |
| { |
| entry->fde.start = bytes; |
| entry->fde.end = limit; |
| } |
| |
| return 0; |
| } |
| INTDEF (dwarf_next_cfi) |