summaryrefslogtreecommitdiffstats
path: root/src/libdw/fde.c
diff options
context:
space:
mode:
authorChih-hung Hsieh <chh@google.com>2015-09-25 14:51:48 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-09-25 14:51:48 +0000
commitb0121c5547604527aaeea297b54047cd14b234df (patch)
tree7d9031ee3d5796de4a1825892fc6e04ba6e36ae2 /src/libdw/fde.c
parentd03895cf5f8b77c6a85abcd84ea0d80ff56be846 (diff)
parent5eafdf0f9bfd9a3c5f93414ac16bb399b6da0b7f (diff)
downloadandroid_external_elfutils-b0121c5547604527aaeea297b54047cd14b234df.tar.gz
android_external_elfutils-b0121c5547604527aaeea297b54047cd14b234df.tar.bz2
android_external_elfutils-b0121c5547604527aaeea297b54047cd14b234df.zip
Merge "Move files up to match upstream source structure."
Diffstat (limited to 'src/libdw/fde.c')
-rw-r--r--src/libdw/fde.c297
1 files changed, 0 insertions, 297 deletions
diff --git a/src/libdw/fde.c b/src/libdw/fde.c
deleted file mode 100644
index 18a522bd..00000000
--- a/src/libdw/fde.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/* FDE reading.
- Copyright (C) 2009-2010, 2014 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 <search.h>
-#include <stdlib.h>
-
-#include "encoded-value.h"
-
-static int
-compare_fde (const void *a, const void *b)
-{
- const struct dwarf_fde *fde1 = a;
- const struct dwarf_fde *fde2 = b;
-
- /* Find out which of the two arguments is the search value.
- It has end offset 0. */
- if (fde1->end == 0)
- {
- if (fde1->start < fde2->start)
- return -1;
- if (fde1->start >= fde2->end)
- return 1;
- }
- else
- {
- if (fde2->start < fde1->start)
- return 1;
- if (fde2->start >= fde1->end)
- return -1;
- }
-
- return 0;
-}
-
-static struct dwarf_fde *
-intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
-{
- /* Look up the new entry's CIE. */
- struct dwarf_cie *cie = __libdw_find_cie (cache, entry->CIE_pointer);
- if (cie == NULL)
- return (void *) -1l;
-
- struct dwarf_fde *fde = malloc (sizeof (struct dwarf_fde));
- if (fde == NULL)
- {
- __libdw_seterrno (DWARF_E_NOMEM);
- return NULL;
- }
-
- fde->instructions = entry->start;
- fde->instructions_end = entry->end;
- if (unlikely (read_encoded_value (cache, cie->fde_encoding,
- &fde->instructions, &fde->start))
- || unlikely (read_encoded_value (cache, cie->fde_encoding & 0x0f,
- &fde->instructions, &fde->end)))
- {
- free (fde);
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return NULL;
- }
- fde->end += fde->start;
-
- fde->cie = cie;
-
- if (cie->sized_augmentation_data)
- {
- /* The CIE augmentation says the FDE has a DW_FORM_block
- before its actual instruction stream. */
- Dwarf_Word len;
- get_uleb128 (len, fde->instructions, fde->instructions_end);
- if ((Dwarf_Word) (fde->instructions_end - fde->instructions) < len)
- {
- free (fde);
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return NULL;
- }
- fde->instructions += len;
- }
- else
- /* We had to understand all of the CIE augmentation string.
- We've recorded the number of data bytes in FDEs. */
- fde->instructions += cie->fde_augmentation_data_size;
-
- /* Add the new entry to the search tree. */
- if (tsearch (fde, &cache->fde_tree, &compare_fde) == NULL)
- {
- free (fde);
- __libdw_seterrno (DWARF_E_NOMEM);
- return NULL;
- }
-
- return fde;
-}
-
-struct dwarf_fde *
-internal_function
-__libdw_fde_by_offset (Dwarf_CFI *cache, Dwarf_Off offset)
-{
- Dwarf_CFI_Entry entry;
- Dwarf_Off next_offset;
- int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
- &cache->data->d, CFI_IS_EH (cache),
- offset, &next_offset, &entry);
- if (result != 0)
- {
- if (result > 0)
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return NULL;
- }
-
- if (unlikely (dwarf_cfi_cie_p (&entry)))
- goto invalid;
-
- /* We have a new FDE to consider. */
- struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
- if (fde == (void *) -1l || fde == NULL)
- return NULL;
-
- /* If this happened to be what we would have read next, notice it. */
- if (cache->next_offset == offset)
- cache->next_offset = next_offset;
-
- return fde;
-}
-
-/* Use a binary search table in .eh_frame_hdr format, yield an FDE offset. */
-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,
- cache->search_table_encoding,
- NULL);
-
- /* Dummy used by read_encoded_value. */
- Dwarf_CFI dummy_cfi =
- {
- .e_ident = cache->e_ident,
- .datarel = cache->search_table_vaddr,
- .frame_vaddr = cache->search_table_vaddr,
- };
-
- size_t l = 0, u = cache->search_table_entries;
- while (l < u)
- {
- size_t idx = (l + u) / 2;
-
- const uint8_t *p = &cache->search_table[idx * size];
- Dwarf_Addr start;
- if (unlikely (read_encoded_value (&dummy_cfi,
- cache->search_table_encoding, &p,
- &start)))
- break;
- if (address < start)
- u = idx;
- else
- {
- l = idx + 1;
-
- Dwarf_Addr fde;
- if (unlikely (read_encoded_value (&dummy_cfi,
- cache->search_table_encoding, &p,
- &fde)))
- break;
-
- /* If this is the last entry, its upper bound is assumed to be
- the end of the module.
- XXX really should be end of containing PT_LOAD segment */
- if (l < cache->search_table_entries)
- {
- /* Look at the start address in the following entry. */
- Dwarf_Addr end;
- if (unlikely (read_encoded_value
- (&dummy_cfi, cache->search_table_encoding, &p,
- &end)))
- break;
- if (address >= end)
- continue;
- }
-
- return fde - cache->frame_vaddr;
- }
- }
-
- return (Dwarf_Off) -1l;
-}
-
-struct dwarf_fde *
-internal_function
-__libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
-{
- /* Look for a cached FDE covering this address. */
-
- const struct dwarf_fde fde_key = { .start = address, .end = 0 };
- struct dwarf_fde **found = tfind (&fde_key, &cache->fde_tree, &compare_fde);
- if (found != NULL)
- return *found;
-
- /* Use .eh_frame_hdr binary search table if possible. */
- if (cache->search_table != NULL)
- {
- Dwarf_Off offset = binary_search_fde (cache, address);
- if (offset == (Dwarf_Off) -1l)
- goto no_match;
- struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset);
- if (likely (fde != NULL))
- {
- /* Sanity check the address range. */
- if (unlikely (address < fde->start))
- {
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return NULL;
- }
- /* .eh_frame_hdr does not indicate length covered by FDE. */
- if (unlikely (address >= fde->end))
- goto no_match;
- }
- return fde;
- }
-
- /* It's not there. Read more CFI entries until we find it. */
- while (1)
- {
- Dwarf_Off last_offset = cache->next_offset;
- Dwarf_CFI_Entry entry;
- int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
- &cache->data->d, CFI_IS_EH (cache),
- last_offset, &cache->next_offset,
- &entry);
- if (result > 0)
- break;
- if (result < 0)
- {
- if (cache->next_offset == last_offset)
- /* We couldn't progress past the bogus FDE. */
- break;
- /* Skip the loser and look at the next entry. */
- continue;
- }
-
- if (dwarf_cfi_cie_p (&entry))
- {
- /* This is a CIE, not an FDE. We eagerly intern these
- because the next FDE will usually refer to this CIE. */
- __libdw_intern_cie (cache, last_offset, &entry.cie);
- continue;
- }
-
- /* We have a new FDE to consider. */
- struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
-
- if (fde == (void *) -1l) /* Bad FDE, but we can keep looking. */
- continue;
-
- if (fde == NULL) /* Bad data. */
- return NULL;
-
- /* Is this the one we're looking for? */
- if (fde->start <= address && fde->end > address)
- return fde;
- }
-
- no_match:
- /* We found no FDE covering this address. */
- __libdw_seterrno (DWARF_E_NO_MATCH);
- return NULL;
-}