125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Get CFI from ELF file's exception-handling info.
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2009-2010, 2014 Red Hat, Inc.
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of either
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU Lesser General Public License as published by the Free
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 3 of the License, or (at
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU General Public License as published by the Free
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 2 of the License, or (at
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or both in parallel, as here.
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   General Public License for more details.
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received copies of the GNU General Public License and
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the GNU Lesser General Public License along with this program.  If
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   not, see <http://www.gnu.org/licenses/>.  */
2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifdef HAVE_CONFIG_H
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng# include <config.h>
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
3225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdlib.h>
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <string.h>
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <assert.h>
3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "libdwP.h"
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "cfi.h"
3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "encoded-value.h"
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <dwarf.h>
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4325b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwarf_CFI *
4425b3c049e70834cf33790a28643ab058b507b35cBen Chengallocate_cfi (Elf *elf, GElf_Addr vaddr)
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_CFI *cfi = calloc (1, sizeof *cfi);
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (cfi == NULL)
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdw_seterrno (DWARF_E_NOMEM);
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
5125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  cfi->e_ident = (unsigned char *) elf_getident (elf, NULL);
5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (cfi->e_ident == NULL)
5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      free (cfi);
5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
6025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB)
6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB))
6325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    cfi->other_byte_order = true;
6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  cfi->frame_vaddr = vaddr;
6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  cfi->textrel = 0;		/* XXX ? */
6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  cfi->datarel = 0;		/* XXX ? */
6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return cfi;
7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic const uint8_t *
7325b3c049e70834cf33790a28643ab058b507b35cBen Chengparse_eh_frame_hdr (const uint8_t *hdr, size_t hdr_size, GElf_Addr hdr_vaddr,
7425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    const GElf_Ehdr *ehdr, GElf_Addr *eh_frame_vaddr,
7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    size_t *table_entries, uint8_t *table_encoding)
7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const uint8_t *h = hdr;
7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (*h++ != 1)		/* version */
8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return (void *) -1l;
8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint8_t eh_frame_ptr_encoding = *h++;
8325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint8_t fde_count_encoding = *h++;
8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint8_t fde_table_encoding = *h++;
8525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (eh_frame_ptr_encoding == DW_EH_PE_omit)
8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return (void *) -1l;
8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Dummy used by read_encoded_value.  */
9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data_Scn dummy_cfi_hdr_data =
9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
9225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d = { .d_buf = (void *) hdr, .d_size = hdr_size }
9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_CFI dummy_cfi =
9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .e_ident = ehdr->e_ident,
9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .datarel = hdr_vaddr,
9825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .frame_vaddr = hdr_vaddr,
9925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .data = &dummy_cfi_hdr_data,
10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h,
10325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				    eh_frame_vaddr)))
10425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return (void *) -1l;
10525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (fde_count_encoding != DW_EH_PE_omit)
10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Dwarf_Word fde_count;
10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unlikely (read_encoded_value (&dummy_cfi, fde_count_encoding, &h,
11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng					&fde_count)))
11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return (void *) -1l;
11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (fde_count != 0 && (size_t) fde_count == fde_count
11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && fde_table_encoding != DW_EH_PE_omit
11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128)
11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  *table_entries = fde_count;
11725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  *table_encoding = fde_table_encoding;
11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return h;
11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
12025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return NULL;
12325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
12425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12525b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwarf_CFI *
12625b3c049e70834cf33790a28643ab058b507b35cBen Chenggetcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr)
12725b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (phdr->p_filesz < 4))
12925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    goto invalid;
13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
13225b3c049e70834cf33790a28643ab058b507b35cBen Cheng					 ELF_T_BYTE);
13325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
13525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    invalid_hdr:
13625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    invalid:
13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* XXX might be read error or corrupt phdr */
13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdw_seterrno (DWARF_E_INVALID_CFI);
13925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_Addr eh_frame_ptr;
14303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  size_t search_table_entries = 0;
14403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  uint8_t search_table_encoding = 0;
14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz,
14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng						    phdr->p_vaddr, ehdr,
14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng						    &eh_frame_ptr,
14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng						    &search_table_entries,
14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng						    &search_table_encoding);
15025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (search_table == (void *) -1l)
15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    goto invalid_hdr;
15225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset;
15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_Word eh_frame_size = 0;
15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* XXX we have no way without section headers to know the size
15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng     of the .eh_frame data.  Calculate the largest it might possibly be.
15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng     This won't be wasteful if the file is already mmap'd, but if it isn't
15925b3c049e70834cf33790a28643ab058b507b35cBen Cheng     it might be quite excessive.  */
16025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t filesize;
16125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (elf_rawfile (elf, &filesize) != NULL)
16225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    eh_frame_size = filesize - eh_frame_offset;
16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE);
16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_CFI *cfi = allocate_cfi (elf, eh_frame_ptr);
17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (cfi != NULL)
17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      cfi->data = (Elf_Data_Scn *) data;
17425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (search_table != NULL)
17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  cfi->search_table = search_table;
17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  cfi->search_table_vaddr = phdr->p_vaddr;
17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  cfi->search_table_encoding = search_table_encoding;
18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  cfi->search_table_entries = search_table_entries;
18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return cfi;
18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Search the phdrs for PT_GNU_EH_FRAME.  */
18725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwarf_CFI *
18825b3c049e70834cf33790a28643ab058b507b35cBen Chenggetcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t phnum;
19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return NULL;
19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t i = 0; i < phnum; ++i)
19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Phdr phdr_mem;
19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unlikely (phdr == NULL))
19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return NULL;
20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr->p_type == PT_GNU_EH_FRAME)
20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return getcfi_gnu_eh_frame (elf, ehdr, phdr);
20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  __libdw_seterrno (DWARF_E_NO_DWARF);
20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return NULL;
20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwarf_CFI *
20925b3c049e70834cf33790a28643ab058b507b35cBen Chenggetcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     Elf_Scn *scn, GElf_Shdr *shdr,
21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr)
21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_rawdata (scn, NULL);
21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdw_seterrno (DWARF_E_INVALID_ELF);
21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_CFI *cfi = allocate_cfi (elf, shdr->sh_addr);
22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (cfi != NULL)
22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      cfi->data = (Elf_Data_Scn *) data;
22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (hdr_scn != NULL)
22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (hdr_data != NULL)
22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Addr eh_frame_vaddr;
22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      cfi->search_table_vaddr = hdr_vaddr;
23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      cfi->search_table
23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		= parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size,
23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				      hdr_vaddr, ehdr, &eh_frame_vaddr,
23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				      &cfi->search_table_entries,
23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				      &cfi->search_table_encoding);
23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (cfi->search_table == (void *) -1l)
23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
23725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  free (cfi);
23825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* XXX might be read error or corrupt phdr */
23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  __libdw_seterrno (DWARF_E_INVALID_CFI);
24025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  return NULL;
24125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
24225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Sanity check.  */
24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (unlikely (eh_frame_vaddr != shdr->sh_addr))
24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		cfi->search_table = NULL;
24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
24925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return cfi;
25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Search for the sections named ".eh_frame" and ".eh_frame_hdr".  */
25325b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic Dwarf_CFI *
25425b3c049e70834cf33790a28643ab058b507b35cBen Chenggetcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t shstrndx;
25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (elf_getshdrstrndx (elf, &shstrndx) != 0)
25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shstrndx != 0)
26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf_Scn *hdr_scn = NULL;
26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Addr hdr_vaddr = 0;
26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf_Scn *scn = NULL;
26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      while ((scn = elf_nextscn (elf, scn)) != NULL)
26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr shdr_mem;
27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (shdr == NULL)
27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    continue;
27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (name == NULL)
27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    continue;
27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (!strcmp (name, ".eh_frame_hdr"))
27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      hdr_scn = scn;
28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      hdr_vaddr = shdr->sh_addr;
28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
28225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (!strcmp (name, ".eh_frame"))
28303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
28403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (shdr->sh_type == SHT_PROGBITS)
28503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
28603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					    hdr_scn, hdr_vaddr);
28703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      else
28803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		return NULL;
28903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
29125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return (void *) -1l;
29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29625b3c049e70834cf33790a28643ab058b507b35cBen ChengDwarf_CFI *
29725b3c049e70834cf33790a28643ab058b507b35cBen Chengdwarf_getcfi_elf (elf)
29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng     Elf *elf;
29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (elf_kind (elf) != ELF_K_ELF)
30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdw_seterrno (DWARF_E_NOELF);
30325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Ehdr ehdr_mem;
30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (ehdr == NULL))
30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdw_seterrno (DWARF_E_INVALID_ELF);
31125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
31325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_CFI *result = getcfi_shdr (elf, ehdr);
31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (result == (void *) -1l)
31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    result = getcfi_phdr (elf, ehdr);
31725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return result;
31925b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
32025b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwarf_getcfi_elf)
321