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, const GElf_Ehdr *ehdr, 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 cfi->e_machine = ehdr->e_machine;
63 if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB)
64 || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB))
65 cfi->other_byte_order = true;
67 cfi->frame_vaddr = vaddr;
68 cfi->textrel = 0; /* XXX ? */
69 cfi->datarel = 0; /* XXX ? */
74 static const uint8_t *
75 parse_eh_frame_hdr (const uint8_t *hdr, size_t hdr_size, GElf_Addr hdr_vaddr,
76 const GElf_Ehdr *ehdr, GElf_Addr *eh_frame_vaddr,
77 size_t *table_entries, uint8_t *table_encoding)
79 const uint8_t *h = hdr;
81 if (hdr_size < 4 || *h++ != 1) /* version */
84 uint8_t eh_frame_ptr_encoding = *h++;
85 uint8_t fde_count_encoding = *h++;
86 uint8_t fde_table_encoding = *h++;
88 if (eh_frame_ptr_encoding == DW_EH_PE_omit)
91 /* Dummy used by read_encoded_value. */
92 Elf_Data_Scn dummy_cfi_hdr_data =
94 .d = { .d_buf = (void *) hdr, .d_size = hdr_size }
98 .e_ident = ehdr->e_ident,
100 .frame_vaddr = hdr_vaddr,
101 .data = &dummy_cfi_hdr_data,
104 if (unlikely (read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h,
108 if (fde_count_encoding != DW_EH_PE_omit)
110 Dwarf_Word fde_count;
111 if (unlikely (read_encoded_value (&dummy_cfi, fde_count_encoding, &h,
114 if (fde_count != 0 && (size_t) fde_count == fde_count
115 && fde_table_encoding != DW_EH_PE_omit
116 && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128)
118 *table_entries = fde_count;
119 *table_encoding = fde_table_encoding;
128 getcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr)
130 Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
132 if (data == NULL || data->d_buf == NULL)
135 /* XXX might be read error or corrupt phdr */
136 __libdw_seterrno (DWARF_E_INVALID_CFI);
141 Dwarf_Addr eh_frame_ptr;
142 size_t search_table_entries = 0;
143 uint8_t search_table_encoding = 0;
144 const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz,
147 &search_table_entries,
148 &search_table_encoding);
150 /* Make sure there is enough room for the entries in the table,
151 each entry consists of 2 encoded values. */
152 vsize = encoded_value_size (data, ehdr->e_ident, search_table_encoding,
154 dmax = phdr->p_filesz - (search_table - (const uint8_t *) data->d_buf);
155 if (unlikely (search_table == (void *) -1l
157 || search_table_entries > (dmax / vsize) / 2))
160 Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset;
161 Dwarf_Word eh_frame_size = 0;
163 /* XXX we have no way without section headers to know the size
164 of the .eh_frame data. Calculate the largest it might possibly be.
165 This won't be wasteful if the file is already mmap'd, but if it isn't
166 it might be quite excessive. */
168 if (elf_rawfile (elf, &filesize) != NULL)
169 eh_frame_size = filesize - eh_frame_offset;
171 data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE);
174 __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
177 Dwarf_CFI *cfi = allocate_cfi (elf, ehdr, eh_frame_ptr);
180 cfi->data = (Elf_Data_Scn *) data;
182 if (search_table != NULL)
184 cfi->search_table = search_table;
185 cfi->search_table_len = phdr->p_filesz;
186 cfi->search_table_vaddr = phdr->p_vaddr;
187 cfi->search_table_encoding = search_table_encoding;
188 cfi->search_table_entries = search_table_entries;
194 /* Search the phdrs for PT_GNU_EH_FRAME. */
196 getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
199 if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
202 for (size_t i = 0; i < phnum; ++i)
205 GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
206 if (unlikely (phdr == NULL))
208 if (phdr->p_type == PT_GNU_EH_FRAME)
209 return getcfi_gnu_eh_frame (elf, ehdr, phdr);
212 __libdw_seterrno (DWARF_E_NO_DWARF);
217 getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
218 Elf_Scn *scn, GElf_Shdr *shdr,
219 Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr)
221 Elf_Data *data = elf_rawdata (scn, NULL);
222 if (data == NULL || data->d_buf == NULL)
224 __libdw_seterrno (DWARF_E_INVALID_ELF);
227 Dwarf_CFI *cfi = allocate_cfi (elf, ehdr, shdr->sh_addr);
230 cfi->data = (Elf_Data_Scn *) data;
233 Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
234 if (hdr_data != NULL && hdr_data->d_buf != NULL)
237 GElf_Addr eh_frame_vaddr;
238 cfi->search_table_vaddr = hdr_vaddr;
240 = parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size,
241 hdr_vaddr, ehdr, &eh_frame_vaddr,
242 &cfi->search_table_entries,
243 &cfi->search_table_encoding);
244 cfi->search_table_len = hdr_data->d_size;
246 /* Make sure there is enough room for the entries in the table,
247 each entry consists of 2 encoded values. */
248 vsize = encoded_value_size (hdr_data, ehdr->e_ident,
249 cfi->search_table_encoding, NULL);
250 dmax = hdr_data->d_size - (cfi->search_table
251 - (const uint8_t *) hdr_data->d_buf);
252 if (unlikely (cfi->search_table == (void *) -1l
254 || cfi->search_table_entries > (dmax / vsize) / 2))
257 /* XXX might be read error or corrupt phdr */
258 __libdw_seterrno (DWARF_E_INVALID_CFI);
263 if (unlikely (eh_frame_vaddr != shdr->sh_addr))
264 cfi->search_table = NULL;
271 /* Search for the sections named ".eh_frame" and ".eh_frame_hdr". */
273 getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
276 if (elf_getshdrstrndx (elf, &shstrndx) != 0)
278 __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
284 Elf_Scn *hdr_scn = NULL;
285 GElf_Addr hdr_vaddr = 0;
287 while ((scn = elf_nextscn (elf, scn)) != NULL)
290 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
293 const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
296 if (!strcmp (name, ".eh_frame_hdr"))
299 hdr_vaddr = shdr->sh_addr;
301 else if (!strcmp (name, ".eh_frame"))
303 if (shdr->sh_type != SHT_NOBITS)
304 return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
316 dwarf_getcfi_elf (Elf *elf)
318 if (elf_kind (elf) != ELF_K_ELF)
320 __libdw_seterrno (DWARF_E_NOELF);
325 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
326 if (unlikely (ehdr == NULL))
328 __libdw_seterrno (DWARF_E_INVALID_ELF);
332 Dwarf_CFI *result = getcfi_shdr (elf, ehdr);
333 if (result == (void *) -1l)
334 result = getcfi_phdr (elf, ehdr);
338 INTDEF (dwarf_getcfi_elf)