1 /* Get CFI from ELF file's exception-handling info.
2 Copyright (C) 2009-2010 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 (*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 if (unlikely (phdr->p_filesz < 4))
131 Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
137 /* XXX might be read error or corrupt phdr */
138 __libdw_seterrno (DWARF_E_INVALID_CFI);
142 Dwarf_Addr eh_frame_ptr;
143 size_t search_table_entries;
144 uint8_t search_table_encoding;
145 const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz,
148 &search_table_entries,
149 &search_table_encoding);
150 if (search_table == (void *) -1l)
153 Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset;
154 Dwarf_Word eh_frame_size = 0;
156 /* XXX we have no way without section headers to know the size
157 of the .eh_frame data. Calculate the largest it might possibly be.
158 This won't be wasteful if the file is already mmap'd, but if it isn't
159 it might be quite excessive. */
161 if (elf_rawfile (elf, &filesize) != NULL)
162 eh_frame_size = filesize - eh_frame_offset;
164 data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE);
167 __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
170 Dwarf_CFI *cfi = allocate_cfi (elf, eh_frame_ptr);
173 cfi->data = (Elf_Data_Scn *) data;
175 if (search_table != NULL)
177 cfi->search_table = search_table;
178 cfi->search_table_vaddr = phdr->p_vaddr;
179 cfi->search_table_encoding = search_table_encoding;
180 cfi->search_table_entries = search_table_entries;
186 /* Search the phdrs for PT_GNU_EH_FRAME. */
188 getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
191 if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
194 for (size_t i = 0; i < phnum; ++i)
197 GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
198 if (unlikely (phdr == NULL))
200 if (phdr->p_type == PT_GNU_EH_FRAME)
201 return getcfi_gnu_eh_frame (elf, ehdr, phdr);
204 __libdw_seterrno (DWARF_E_NO_DWARF);
209 getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
210 Elf_Scn *scn, GElf_Shdr *shdr,
211 Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr)
213 Elf_Data *data = elf_rawdata (scn, NULL);
216 __libdw_seterrno (DWARF_E_INVALID_ELF);
219 Dwarf_CFI *cfi = allocate_cfi (elf, shdr->sh_addr);
222 cfi->data = (Elf_Data_Scn *) data;
225 Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
226 if (hdr_data != NULL)
228 GElf_Addr eh_frame_vaddr;
229 cfi->search_table_vaddr = hdr_vaddr;
231 = parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size,
232 hdr_vaddr, ehdr, &eh_frame_vaddr,
233 &cfi->search_table_entries,
234 &cfi->search_table_encoding);
235 if (cfi->search_table == (void *) -1l)
238 /* XXX might be read error or corrupt phdr */
239 __libdw_seterrno (DWARF_E_INVALID_CFI);
244 if (unlikely (eh_frame_vaddr != shdr->sh_addr))
245 cfi->search_table = NULL;
252 /* Search for the sections named ".eh_frame" and ".eh_frame_hdr". */
254 getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
257 if (elf_getshdrstrndx (elf, &shstrndx) != 0)
259 __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
265 Elf_Scn *hdr_scn = NULL;
266 GElf_Addr hdr_vaddr = 0;
268 while ((scn = elf_nextscn (elf, scn)) != NULL)
271 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
274 const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
277 if (!strcmp (name, ".eh_frame_hdr"))
280 hdr_vaddr = shdr->sh_addr;
282 else if (!strcmp (name, ".eh_frame"))
283 return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
292 dwarf_getcfi_elf (elf)
295 if (elf_kind (elf) != ELF_K_ELF)
297 __libdw_seterrno (DWARF_E_NOELF);
302 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
303 if (unlikely (ehdr == NULL))
305 __libdw_seterrno (DWARF_E_INVALID_ELF);
309 Dwarf_CFI *result = getcfi_shdr (elf, ehdr);
310 if (result == (void *) -1l)
311 result = getcfi_phdr (elf, ehdr);
315 INTDEF (dwarf_getcfi_elf)