2 Copyright (C) 2009-2010 Red Hat, Inc.
3 This file is part of Red Hat elfutils.
5 Red Hat elfutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by the
7 Free Software Foundation; version 2 of the License.
9 Red Hat elfutils is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with Red Hat elfutils; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18 In addition, as a special exception, Red Hat, Inc. gives You the
19 additional right to link the code of Red Hat elfutils with code licensed
20 under any Open Source Initiative certified open source license
21 (http://www.opensource.org/licenses/index.php) which requires the
22 distribution of source code with any binary distribution and to
23 distribute linked combinations of the two. Non-GPL Code permitted under
24 this exception must only link to the code of Red Hat elfutils through
25 those well defined interfaces identified in the file named EXCEPTION
26 found in the source code files (the "Approved Interfaces"). The files
27 of Non-GPL Code may instantiate templates or use macros or inline
28 functions from the Approved Interfaces without causing the resulting
29 work to be covered by the GNU General Public License. Only Red Hat,
30 Inc. may make changes or additions to the list of Approved Interfaces.
31 Red Hat's grant of this exception is conditioned upon your not adding
32 any new exceptions. If you wish to add a new Approved Interface or
33 exception, please contact Red Hat. You must obey the GNU General Public
34 License in all respects for all of the Red Hat elfutils code and other
35 code used in conjunction with Red Hat elfutils except the Non-GPL Code
36 covered by this exception. If you modify this file, you may extend this
37 exception to your version of the file, but you are not obligated to do
38 so. If you do not wish to provide this exception without modification,
39 you must delete this exception statement from your version and license
40 this file solely under the GPL without exception.
42 Red Hat elfutils is an included package of the Open Invention Network.
43 An included package of the Open Invention Network is a package for which
44 Open Invention Network licensees cross-license their patents. No patent
45 license is granted, either expressly or impliedly, by designation as an
46 included package. Should you wish to participate in the Open Invention
47 Network licensing program, please visit www.openinventionnetwork.com
48 <http://www.openinventionnetwork.com>. */
58 #include "encoded-value.h"
61 compare_fde (const void *a, const void *b)
63 const struct dwarf_fde *fde1 = a;
64 const struct dwarf_fde *fde2 = b;
66 /* Find out which of the two arguments is the search value.
67 It has end offset 0. */
70 if (fde1->start < fde2->start)
72 if (fde1->start >= fde2->end)
77 if (fde2->start < fde1->start)
79 if (fde2->start >= fde1->end)
86 static struct dwarf_fde *
87 intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
89 /* Look up the new entry's CIE. */
90 struct dwarf_cie *cie = __libdw_find_cie (cache, entry->CIE_pointer);
94 struct dwarf_fde *fde = malloc (sizeof (struct dwarf_fde));
97 __libdw_seterrno (DWARF_E_NOMEM);
101 fde->instructions = entry->start;
102 fde->instructions_end = entry->end;
103 if (unlikely (read_encoded_value (cache, cie->fde_encoding,
104 &fde->instructions, &fde->start))
105 || unlikely (read_encoded_value (cache, cie->fde_encoding & 0x0f,
106 &fde->instructions, &fde->end)))
108 fde->end += fde->start;
112 if (cie->sized_augmentation_data)
114 /* The CIE augmentation says the FDE has a DW_FORM_block
115 before its actual instruction stream. */
117 get_uleb128 (len, fde->instructions);
118 if ((Dwarf_Word) (fde->instructions_end - fde->instructions) < len)
121 __libdw_seterrno (DWARF_E_INVALID_DWARF);
124 fde->instructions += len;
127 /* We had to understand all of the CIE augmentation string.
128 We've recorded the number of data bytes in FDEs. */
129 fde->instructions += cie->fde_augmentation_data_size;
131 /* Add the new entry to the search tree. */
132 if (tsearch (fde, &cache->fde_tree, &compare_fde) == NULL)
135 __libdw_seterrno (DWARF_E_NOMEM);
144 __libdw_fde_by_offset (Dwarf_CFI *cache, Dwarf_Off offset)
146 Dwarf_CFI_Entry entry;
147 Dwarf_Off next_offset;
148 int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
149 &cache->data->d, CFI_IS_EH (cache),
150 offset, &next_offset, &entry);
155 __libdw_seterrno (DWARF_E_INVALID_DWARF);
159 if (unlikely (dwarf_cfi_cie_p (&entry)))
162 /* We have a new FDE to consider. */
163 struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
164 if (fde == (void *) -1l || fde == NULL)
167 /* If this happened to be what we would have read next, notice it. */
168 if (cache->next_offset == offset)
169 cache->next_offset = next_offset;
174 /* Use a binary search table in .eh_frame_hdr format, yield an FDE offset. */
176 binary_search_fde (Dwarf_CFI *cache, Dwarf_Addr address)
178 const size_t size = 2 * encoded_value_size (&cache->data->d, cache->e_ident,
179 cache->search_table_encoding,
182 /* Dummy used by read_encoded_value. */
183 Dwarf_CFI dummy_cfi =
185 .e_ident = cache->e_ident,
186 .datarel = cache->search_table_vaddr,
187 .frame_vaddr = cache->search_table_vaddr,
190 size_t l = 0, u = cache->search_table_entries;
193 size_t idx = (l + u) / 2;
195 const uint8_t *p = &cache->search_table[idx * size];
197 if (unlikely (read_encoded_value (&dummy_cfi,
198 cache->search_table_encoding, &p,
206 if (unlikely (read_encoded_value (&dummy_cfi,
207 cache->search_table_encoding, &p,
210 if (address >= start)
214 /* If this is the last entry, its upper bound is assumed to be
215 the end of the module.
216 XXX really should be end of containing PT_LOAD segment */
217 if (l < cache->search_table_entries)
219 /* Look at the start address in the following entry. */
221 if (unlikely (read_encoded_value
222 (&dummy_cfi, cache->search_table_encoding, &p,
229 return fde - cache->frame_vaddr;
234 return (Dwarf_Off) -1l;
239 __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
241 /* Look for a cached FDE covering this address. */
243 const struct dwarf_fde fde_key = { .start = address, .end = 0 };
244 struct dwarf_fde **found = tfind (&fde_key, &cache->fde_tree, &compare_fde);
248 /* Use .eh_frame_hdr binary search table if possible. */
249 if (cache->search_table != NULL)
251 Dwarf_Off offset = binary_search_fde (cache, address);
252 if (offset == (Dwarf_Off) -1l)
254 struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset);
255 if (unlikely (fde != NULL)
256 /* Sanity check the address range. */
257 && unlikely (address < fde->start || address >= fde->end))
259 __libdw_seterrno (DWARF_E_INVALID_DWARF);
265 /* It's not there. Read more CFI entries until we find it. */
268 Dwarf_Off last_offset = cache->next_offset;
269 Dwarf_CFI_Entry entry;
270 int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
271 &cache->data->d, CFI_IS_EH (cache),
272 last_offset, &cache->next_offset,
278 if (cache->next_offset == last_offset)
279 /* We couldn't progress past the bogus FDE. */
281 /* Skip the loser and look at the next entry. */
285 if (dwarf_cfi_cie_p (&entry))
287 /* This is a CIE, not an FDE. We eagerly intern these
288 because the next FDE will usually refer to this CIE. */
289 __libdw_intern_cie (cache, last_offset, &entry.cie);
293 /* We have a new FDE to consider. */
294 struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
296 if (fde == (void *) -1l) /* Bad FDE, but we can keep looking. */
299 if (fde == NULL) /* Bad data. */
302 /* Is this the one we're looking for? */
303 if (fde->start <= address && fde->end > address)
308 /* We found no FDE covering this address. */
309 __libdw_seterrno (DWARF_E_NO_MATCH);