1 /* Get CFI from ELF file's exception-handling info.
2 Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
39 #include "encoded-value.h"
44 allocate_cfi (Elf *elf, GElf_Addr vaddr)
46 Dwarf_CFI *cfi = calloc (1, sizeof *cfi);
49 __libdw_seterrno (DWARF_E_NOMEM);
53 cfi->e_ident = (unsigned char *) elf_getident (elf, NULL);
54 if (cfi->e_ident == NULL)
57 __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
61 if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB)
62 || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB))
63 cfi->other_byte_order = true;
65 cfi->frame_vaddr = vaddr;
66 cfi->textrel = 0; /* XXX ? */
67 cfi->datarel = 0; /* XXX ? */
72 static const uint8_t *
73 parse_eh_frame_hdr (const uint8_t *hdr, size_t hdr_size, GElf_Addr hdr_vaddr,
74 const GElf_Ehdr *ehdr, GElf_Addr *eh_frame_vaddr,
75 size_t *table_entries, uint8_t *table_encoding)
77 const uint8_t *h = hdr;
79 if (hdr_size < 4 || *h++ != 1) /* version */
82 uint8_t eh_frame_ptr_encoding = *h++;
83 uint8_t fde_count_encoding = *h++;
84 uint8_t fde_table_encoding = *h++;
86 if (eh_frame_ptr_encoding == DW_EH_PE_omit)
89 /* Dummy used by read_encoded_value. */
90 Elf_Data_Scn dummy_cfi_hdr_data =
92 .d = { .d_buf = (void *) hdr, .d_size = hdr_size }
96 .e_ident = ehdr->e_ident,
98 .frame_vaddr = hdr_vaddr,
99 .data = &dummy_cfi_hdr_data,
102 if (unlikely (read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h,
106 if (fde_count_encoding != DW_EH_PE_omit)
108 Dwarf_Word fde_count;
109 if (unlikely (read_encoded_value (&dummy_cfi, fde_count_encoding, &h,
112 if (fde_count != 0 && (size_t) fde_count == fde_count
113 && fde_table_encoding != DW_EH_PE_omit
114 && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128)
116 *table_entries = fde_count;
117 *table_encoding = fde_table_encoding;
126 getcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr)
128 Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
130 if (data == NULL || data->d_buf == NULL)
133 /* XXX might be read error or corrupt phdr */
134 __libdw_seterrno (DWARF_E_INVALID_CFI);
139 Dwarf_Addr eh_frame_ptr;
140 size_t search_table_entries = 0;
141 uint8_t search_table_encoding = 0;
142 const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz,
145 &search_table_entries,
146 &search_table_encoding);
148 /* Make sure there is enough room for the entries in the table,
149 each entry consists of 2 encoded values. */
150 vsize = encoded_value_size (data, ehdr->e_ident, search_table_encoding,
152 dmax = phdr->p_filesz - (search_table - (const uint8_t *) data->d_buf);
153 if (unlikely (search_table == (void *) -1l
155 || search_table_entries > (dmax / vsize) / 2))
158 Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset;
159 Dwarf_Word eh_frame_size = 0;
161 /* XXX we have no way without section headers to know the size
162 of the .eh_frame data. Calculate the largest it might possibly be.
163 This won't be wasteful if the file is already mmap'd, but if it isn't
164 it might be quite excessive. */
166 if (elf_rawfile (elf, &filesize) != NULL)
167 eh_frame_size = filesize - eh_frame_offset;
169 data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE);
172 __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
175 Dwarf_CFI *cfi = allocate_cfi (elf, eh_frame_ptr);
178 cfi->data = (Elf_Data_Scn *) data;
180 if (search_table != NULL)
182 cfi->search_table = search_table;
183 cfi->search_table_len = phdr->p_filesz;
184 cfi->search_table_vaddr = phdr->p_vaddr;
185 cfi->search_table_encoding = search_table_encoding;
186 cfi->search_table_entries = search_table_entries;
192 /* Search the phdrs for PT_GNU_EH_FRAME. */
194 getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
197 if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
200 for (size_t i = 0; i < phnum; ++i)
203 GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
204 if (unlikely (phdr == NULL))
206 if (phdr->p_type == PT_GNU_EH_FRAME)
207 return getcfi_gnu_eh_frame (elf, ehdr, phdr);
210 __libdw_seterrno (DWARF_E_NO_DWARF);
215 getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
216 Elf_Scn *scn, GElf_Shdr *shdr,
217 Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr)
219 Elf_Data *data = elf_rawdata (scn, NULL);
220 if (data == NULL || data->d_buf == NULL)
222 __libdw_seterrno (DWARF_E_INVALID_ELF);
225 Dwarf_CFI *cfi = allocate_cfi (elf, shdr->sh_addr);
228 cfi->data = (Elf_Data_Scn *) data;
231 Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
232 if (hdr_data != NULL && hdr_data->d_buf != NULL)
235 GElf_Addr eh_frame_vaddr;
236 cfi->search_table_vaddr = hdr_vaddr;
238 = parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size,
239 hdr_vaddr, ehdr, &eh_frame_vaddr,
240 &cfi->search_table_entries,
241 &cfi->search_table_encoding);
242 cfi->search_table_len = hdr_data->d_size;
244 /* Make sure there is enough room for the entries in the table,
245 each entry consists of 2 encoded values. */
246 vsize = encoded_value_size (hdr_data, ehdr->e_ident,
247 cfi->search_table_encoding, NULL);
248 dmax = hdr_data->d_size - (cfi->search_table
249 - (const uint8_t *) hdr_data->d_buf);
250 if (unlikely (cfi->search_table == (void *) -1l
252 || cfi->search_table_entries > (dmax / vsize) / 2))
255 /* XXX might be read error or corrupt phdr */
256 __libdw_seterrno (DWARF_E_INVALID_CFI);
261 if (unlikely (eh_frame_vaddr != shdr->sh_addr))
262 cfi->search_table = NULL;
269 /* Search for the sections named ".eh_frame" and ".eh_frame_hdr". */
271 getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
274 if (elf_getshdrstrndx (elf, &shstrndx) != 0)
276 __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
282 Elf_Scn *hdr_scn = NULL;
283 GElf_Addr hdr_vaddr = 0;
285 while ((scn = elf_nextscn (elf, scn)) != NULL)
288 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
291 const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
294 if (!strcmp (name, ".eh_frame_hdr"))
297 hdr_vaddr = shdr->sh_addr;
299 else if (!strcmp (name, ".eh_frame"))
301 if (shdr->sh_type != SHT_NOBITS)
302 return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
314 dwarf_getcfi_elf (Elf *elf)
316 if (elf_kind (elf) != ELF_K_ELF)
318 __libdw_seterrno (DWARF_E_NOELF);
323 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
324 if (unlikely (ehdr == NULL))
326 __libdw_seterrno (DWARF_E_INVALID_ELF);
330 Dwarf_CFI *result = getcfi_shdr (elf, ehdr);
331 if (result == (void *) -1l)
332 result = getcfi_phdr (elf, ehdr);
336 INTDEF (dwarf_getcfi_elf)