From: Roland McGrath Date: Thu, 24 Jun 2010 23:47:17 +0000 (-0700) Subject: Always canonicalize stored encodings. Prepare for CIEs with varying address_size. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=585990860c6d0927d991887a8ab89dc00bcd81dc;p=thirdparty%2Felfutils.git Always canonicalize stored encodings. Prepare for CIEs with varying address_size. --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index b671da8ff..59fbb8aad 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,16 @@ +2010-06-24 Roland McGrath + + * encoded-value.h (encoded_value_size): Replace E_IDENT parameter + with ADDRESS_SIZE. + (read_encoded_value): Update caller. + * fde.c (binary_search_fde): Likewise. + * dwarf_next_cfi.c: Likewise. + * cfi.h (struct dwarf_cie): New member address_size. + (CFI_ADDRSIZE): New macro. + * cie.c (intern_new_cie): Initialize and use CIE->address_size. + (canonicalize_encoding): New function. + (intern_new_cie): Call it, do both FDE and LSDA encodings. + 2010-06-23 Roland McGrath * cfi.c (dwarf_cfi_validate_fde): Function removed. diff --git a/libdw/cfi.h b/libdw/cfi.h index b300b73df..3dab7fb84 100644 --- a/libdw/cfi.h +++ b/libdw/cfi.h @@ -71,7 +71,11 @@ struct dwarf_cie const Dwarf_Frame *initial_state; - uint8_t fde_encoding; /* DW_EH_PE_* for addresses in FDEs. */ + uint8_t address_size; /* Address size used here. */ + + /* These encodings are canonicalized from DW_EH_PE_absptr + to a particular size DW_EH_PE_udata[48]. */ + uint8_t fde_encoding; /* DW_EH_PE_* for addresses in FDEs. */ uint8_t lsda_encoding; /* DW_EH_PE_* for LSDA in FDE augmentation. */ bool sized_augmentation_data; /* Saw 'z': FDEs have self-sized data. */ @@ -142,6 +146,8 @@ struct Dwarf_CFI_s bool default_same_value; }; +#define CFI_ADDRSIZE(cache) (cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8) + enum dwarf_frame_rule { diff --git a/libdw/cie.c b/libdw/cie.c index 7c93f5510..7e111f17e 100644 --- a/libdw/cie.c +++ b/libdw/cie.c @@ -70,6 +70,29 @@ compare_cie (const void *a, const void *b) return 0; } +/* Canonicalize encoding to a specific size. */ +static bool +canonicalize_encoding (uint8_t *encoding, uint8_t address_size) +{ + if ((*encoding & 0x07) == DW_EH_PE_absptr) + { + assert (DW_EH_PE_absptr == 0); + + switch (address_size) + { + case 8: + *encoding |= DW_EH_PE_udata8; + break; + case 4: + *encoding |= DW_EH_PE_udata4; + break; + default: + return true; + } + } + return false; +} + /* There is no CIE at OFFSET in the tree. Add it. */ static struct dwarf_cie * intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) @@ -90,6 +113,9 @@ intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) cie->sized_augmentation_data = false; cie->signal_frame = false; + /* XXX should get from dwarf_next_cfi with v4 header. */ + cie->address_size = CFI_ADDRSIZE (cache); + cie->fde_encoding = DW_EH_PE_absptr; cie->lsda_encoding = DW_EH_PE_omit; @@ -112,7 +138,7 @@ intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) cie->lsda_encoding = *data++; if (!cie->sized_augmentation_data) cie->fde_augmentation_data_size - += encoded_value_size (&cache->data->d, cache->e_ident, + += encoded_value_size (&cache->data->d, cie->address_size, cie->lsda_encoding, NULL); continue; @@ -122,7 +148,7 @@ intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) case 'P': /* Skip personality routine. */ encoding = *data++; - data += encoded_value_size (&cache->data->d, cache->e_ident, + data += encoded_value_size (&cache->data->d, cie->address_size, encoding, data); continue; @@ -136,27 +162,12 @@ intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) break; } - if ((cie->fde_encoding & 0x0f) == DW_EH_PE_absptr) + if (canonicalize_encoding (&cie->fde_encoding, cie->address_size) + || canonicalize_encoding (&cie->lsda_encoding, cie->address_size)) { - /* Canonicalize encoding to a specific size. */ - assert (DW_EH_PE_absptr == 0); - - /* XXX should get from dwarf_next_cfi with v4 header. */ - uint_fast8_t address_size - = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; - switch (address_size) - { - case 8: - cie->fde_encoding |= DW_EH_PE_udata8; - break; - case 4: - cie->fde_encoding |= DW_EH_PE_udata4; - break; - default: - free (cie); - __libdw_seterrno (DWARF_E_INVALID_DWARF); - return NULL; - } + free (cie); + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; } /* Save the initial instructions to be played out into initial state. */ diff --git a/libdw/dwarf_next_cfi.c b/libdw/dwarf_next_cfi.c index 0e90457d0..49791c981 100644 --- a/libdw/dwarf_next_cfi.c +++ b/libdw/dwarf_next_cfi.c @@ -224,11 +224,12 @@ dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry) case 'R': /* Skip FDE address encoding byte. */ encoding = *bytes++; entry->cie.fde_augmentation_data_size - += encoded_value_size (data, e_ident, encoding, NULL); + += encoded_value_size (data, address_size, encoding, NULL); continue; case 'P': /* Skip encoded personality routine pointer. */ encoding = *bytes++; - bytes += encoded_value_size (data, e_ident, encoding, bytes); + bytes += encoded_value_size (data, address_size, + encoding, bytes); continue; case 'S': /* Skip signal-frame flag. */ continue; diff --git a/libdw/encoded-value.h b/libdw/encoded-value.h index e118a1c4d..ee8a6f31a 100644 --- a/libdw/encoded-value.h +++ b/libdw/encoded-value.h @@ -56,7 +56,7 @@ static size_t __attribute__ ((unused)) -encoded_value_size (const Elf_Data *data, const unsigned char e_ident[], +encoded_value_size (const Elf_Data *data, uint8_t address_size, uint8_t encoding, const uint8_t *p) { if (encoding == DW_EH_PE_omit) @@ -72,7 +72,7 @@ encoded_value_size (const Elf_Data *data, const unsigned char e_ident[], return 8; case DW_EH_PE_absptr: - return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + return address_size; case DW_EH_PE_uleb128: if (p != NULL) @@ -84,7 +84,6 @@ encoded_value_size (const Elf_Data *data, const unsigned char e_ident[], } default: - abort (); return 0; } } @@ -136,7 +135,8 @@ read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, const uint8_t **p, break; case DW_EH_PE_aligned: { - const size_t size = encoded_value_size (&cache->data->d, cache->e_ident, + const size_t size = encoded_value_size (&cache->data->d, + CFI_ADDRSIZE (cache), encoding, *p); size_t align = ((cache->frame_vaddr + (*p - (const uint8_t *) cache->data->d.d_buf)) @@ -203,7 +203,7 @@ read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, const uint8_t **p, return true; *result -= cache->frame_vaddr; if (unlikely (*result > (cache->data->d.d_size - - encoded_value_size (NULL, cache->e_ident, + - encoded_value_size (NULL, CFI_ADDRSIZE (cache), DW_EH_PE_absptr, NULL)))) return true; const uint8_t *ptr = cache->data->d.d_buf + *result; diff --git a/libdw/fde.c b/libdw/fde.c index 14e9395da..44a39ccd7 100644 --- a/libdw/fde.c +++ b/libdw/fde.c @@ -199,7 +199,8 @@ __libdw_fde_by_offset (Dwarf_CFI *cache, Dwarf_Off offset, ptrdiff_t *nextoff) static Dwarf_Off binary_search_fde (Dwarf_CFI *cache, Dwarf_Addr address) { - const size_t size = 2 * encoded_value_size (&cache->data->d, cache->e_ident, + const size_t size = 2 * encoded_value_size (&cache->data->d, + CFI_ADDRSIZE (cache), cache->search_table_encoding, NULL);