1da0c48c4Sopenharmony_ci/* Get CFI from ELF file's exception-handling info.
2da0c48c4Sopenharmony_ci   Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci
33da0c48c4Sopenharmony_ci#include <stdlib.h>
34da0c48c4Sopenharmony_ci#include <string.h>
35da0c48c4Sopenharmony_ci#include <assert.h>
36da0c48c4Sopenharmony_ci
37da0c48c4Sopenharmony_ci#include "libdwP.h"
38da0c48c4Sopenharmony_ci#include "cfi.h"
39da0c48c4Sopenharmony_ci#include "encoded-value.h"
40da0c48c4Sopenharmony_ci#include <dwarf.h>
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_cistatic Dwarf_CFI *
44da0c48c4Sopenharmony_ciallocate_cfi (Elf *elf, const GElf_Ehdr *ehdr, GElf_Addr vaddr)
45da0c48c4Sopenharmony_ci{
46da0c48c4Sopenharmony_ci  Dwarf_CFI *cfi = calloc (1, sizeof *cfi);
47da0c48c4Sopenharmony_ci  if (cfi == NULL)
48da0c48c4Sopenharmony_ci    {
49da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_NOMEM);
50da0c48c4Sopenharmony_ci      return NULL;
51da0c48c4Sopenharmony_ci    }
52da0c48c4Sopenharmony_ci
53da0c48c4Sopenharmony_ci  cfi->e_ident = (unsigned char *) elf_getident (elf, NULL);
54da0c48c4Sopenharmony_ci  if (cfi->e_ident == NULL)
55da0c48c4Sopenharmony_ci    {
56da0c48c4Sopenharmony_ci      free (cfi);
57da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
58da0c48c4Sopenharmony_ci      return NULL;
59da0c48c4Sopenharmony_ci    }
60da0c48c4Sopenharmony_ci
61da0c48c4Sopenharmony_ci  cfi->e_machine = ehdr->e_machine;
62da0c48c4Sopenharmony_ci
63da0c48c4Sopenharmony_ci  if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB)
64da0c48c4Sopenharmony_ci      || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB))
65da0c48c4Sopenharmony_ci    cfi->other_byte_order = true;
66da0c48c4Sopenharmony_ci
67da0c48c4Sopenharmony_ci  cfi->frame_vaddr = vaddr;
68da0c48c4Sopenharmony_ci  cfi->textrel = 0;		/* XXX ? */
69da0c48c4Sopenharmony_ci  cfi->datarel = 0;		/* XXX ? */
70da0c48c4Sopenharmony_ci
71da0c48c4Sopenharmony_ci  return cfi;
72da0c48c4Sopenharmony_ci}
73da0c48c4Sopenharmony_ci
74da0c48c4Sopenharmony_cistatic const uint8_t *
75da0c48c4Sopenharmony_ciparse_eh_frame_hdr (const uint8_t *hdr, size_t hdr_size, GElf_Addr hdr_vaddr,
76da0c48c4Sopenharmony_ci		    const GElf_Ehdr *ehdr, GElf_Addr *eh_frame_vaddr,
77da0c48c4Sopenharmony_ci		    size_t *table_entries, uint8_t *table_encoding)
78da0c48c4Sopenharmony_ci{
79da0c48c4Sopenharmony_ci  const uint8_t *h = hdr;
80da0c48c4Sopenharmony_ci
81da0c48c4Sopenharmony_ci  if (hdr_size < 4 || *h++ != 1)		/* version */
82da0c48c4Sopenharmony_ci    return (void *) -1l;
83da0c48c4Sopenharmony_ci
84da0c48c4Sopenharmony_ci  uint8_t eh_frame_ptr_encoding = *h++;
85da0c48c4Sopenharmony_ci  uint8_t fde_count_encoding = *h++;
86da0c48c4Sopenharmony_ci  uint8_t fde_table_encoding = *h++;
87da0c48c4Sopenharmony_ci
88da0c48c4Sopenharmony_ci  if (eh_frame_ptr_encoding == DW_EH_PE_omit)
89da0c48c4Sopenharmony_ci    return (void *) -1l;
90da0c48c4Sopenharmony_ci
91da0c48c4Sopenharmony_ci  /* Dummy used by read_encoded_value.  */
92da0c48c4Sopenharmony_ci  Elf_Data_Scn dummy_cfi_hdr_data =
93da0c48c4Sopenharmony_ci    {
94da0c48c4Sopenharmony_ci      .d = { .d_buf = (void *) hdr, .d_size = hdr_size }
95da0c48c4Sopenharmony_ci    };
96da0c48c4Sopenharmony_ci  Dwarf_CFI dummy_cfi =
97da0c48c4Sopenharmony_ci    {
98da0c48c4Sopenharmony_ci      .e_ident = ehdr->e_ident,
99da0c48c4Sopenharmony_ci      .datarel = hdr_vaddr,
100da0c48c4Sopenharmony_ci      .frame_vaddr = hdr_vaddr,
101da0c48c4Sopenharmony_ci      .data = &dummy_cfi_hdr_data,
102da0c48c4Sopenharmony_ci    };
103da0c48c4Sopenharmony_ci
104da0c48c4Sopenharmony_ci  if (unlikely (read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h,
105da0c48c4Sopenharmony_ci				    eh_frame_vaddr)))
106da0c48c4Sopenharmony_ci    return (void *) -1l;
107da0c48c4Sopenharmony_ci
108da0c48c4Sopenharmony_ci  if (fde_count_encoding != DW_EH_PE_omit)
109da0c48c4Sopenharmony_ci    {
110da0c48c4Sopenharmony_ci      Dwarf_Word fde_count;
111da0c48c4Sopenharmony_ci      if (unlikely (read_encoded_value (&dummy_cfi, fde_count_encoding, &h,
112da0c48c4Sopenharmony_ci					&fde_count)))
113da0c48c4Sopenharmony_ci	return (void *) -1l;
114da0c48c4Sopenharmony_ci      if (fde_count != 0 && (size_t) fde_count == fde_count
115da0c48c4Sopenharmony_ci	  && fde_table_encoding != DW_EH_PE_omit
116da0c48c4Sopenharmony_ci	  && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128)
117da0c48c4Sopenharmony_ci	{
118da0c48c4Sopenharmony_ci	  *table_entries = fde_count;
119da0c48c4Sopenharmony_ci	  *table_encoding = fde_table_encoding;
120da0c48c4Sopenharmony_ci	  return h;
121da0c48c4Sopenharmony_ci	}
122da0c48c4Sopenharmony_ci    }
123da0c48c4Sopenharmony_ci
124da0c48c4Sopenharmony_ci  return NULL;
125da0c48c4Sopenharmony_ci}
126da0c48c4Sopenharmony_ci
127da0c48c4Sopenharmony_cistatic Dwarf_CFI *
128da0c48c4Sopenharmony_cigetcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr)
129da0c48c4Sopenharmony_ci{
130da0c48c4Sopenharmony_ci  Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
131da0c48c4Sopenharmony_ci					 ELF_T_BYTE);
132da0c48c4Sopenharmony_ci  if (data == NULL || data->d_buf == NULL)
133da0c48c4Sopenharmony_ci    {
134da0c48c4Sopenharmony_ci    invalid_hdr:
135da0c48c4Sopenharmony_ci      /* XXX might be read error or corrupt phdr */
136da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_CFI);
137da0c48c4Sopenharmony_ci      return NULL;
138da0c48c4Sopenharmony_ci    }
139da0c48c4Sopenharmony_ci
140da0c48c4Sopenharmony_ci  size_t vsize, dmax;
141da0c48c4Sopenharmony_ci  Dwarf_Addr eh_frame_ptr;
142da0c48c4Sopenharmony_ci  size_t search_table_entries = 0;
143da0c48c4Sopenharmony_ci  uint8_t search_table_encoding = 0;
144da0c48c4Sopenharmony_ci  const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz,
145da0c48c4Sopenharmony_ci						    phdr->p_vaddr, ehdr,
146da0c48c4Sopenharmony_ci						    &eh_frame_ptr,
147da0c48c4Sopenharmony_ci						    &search_table_entries,
148da0c48c4Sopenharmony_ci						    &search_table_encoding);
149da0c48c4Sopenharmony_ci
150da0c48c4Sopenharmony_ci  /* Make sure there is enough room for the entries in the table,
151da0c48c4Sopenharmony_ci     each entry consists of 2 encoded values.  */
152da0c48c4Sopenharmony_ci  vsize = encoded_value_size (data, ehdr->e_ident, search_table_encoding,
153da0c48c4Sopenharmony_ci			      NULL);
154da0c48c4Sopenharmony_ci  dmax = phdr->p_filesz - (search_table - (const uint8_t *) data->d_buf);
155da0c48c4Sopenharmony_ci  if (unlikely (search_table == (void *) -1l
156da0c48c4Sopenharmony_ci		|| vsize == 0
157da0c48c4Sopenharmony_ci		|| search_table_entries > (dmax / vsize) / 2))
158da0c48c4Sopenharmony_ci    goto invalid_hdr;
159da0c48c4Sopenharmony_ci
160da0c48c4Sopenharmony_ci  Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset;
161da0c48c4Sopenharmony_ci  Dwarf_Word eh_frame_size = 0;
162da0c48c4Sopenharmony_ci
163da0c48c4Sopenharmony_ci  /* XXX we have no way without section headers to know the size
164da0c48c4Sopenharmony_ci     of the .eh_frame data.  Calculate the largest it might possibly be.
165da0c48c4Sopenharmony_ci     This won't be wasteful if the file is already mmap'd, but if it isn't
166da0c48c4Sopenharmony_ci     it might be quite excessive.  */
167da0c48c4Sopenharmony_ci  size_t filesize;
168da0c48c4Sopenharmony_ci  if (elf_rawfile (elf, &filesize) != NULL)
169da0c48c4Sopenharmony_ci    eh_frame_size = filesize - eh_frame_offset;
170da0c48c4Sopenharmony_ci
171da0c48c4Sopenharmony_ci  data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE);
172da0c48c4Sopenharmony_ci  if (data == NULL)
173da0c48c4Sopenharmony_ci    {
174da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
175da0c48c4Sopenharmony_ci      return NULL;
176da0c48c4Sopenharmony_ci    }
177da0c48c4Sopenharmony_ci  Dwarf_CFI *cfi = allocate_cfi (elf, ehdr, eh_frame_ptr);
178da0c48c4Sopenharmony_ci  if (cfi != NULL)
179da0c48c4Sopenharmony_ci    {
180da0c48c4Sopenharmony_ci      cfi->data = (Elf_Data_Scn *) data;
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci      if (search_table != NULL)
183da0c48c4Sopenharmony_ci	{
184da0c48c4Sopenharmony_ci	  cfi->search_table = search_table;
185da0c48c4Sopenharmony_ci	  cfi->search_table_len = phdr->p_filesz;
186da0c48c4Sopenharmony_ci	  cfi->search_table_vaddr = phdr->p_vaddr;
187da0c48c4Sopenharmony_ci	  cfi->search_table_encoding = search_table_encoding;
188da0c48c4Sopenharmony_ci	  cfi->search_table_entries = search_table_entries;
189da0c48c4Sopenharmony_ci	}
190da0c48c4Sopenharmony_ci    }
191da0c48c4Sopenharmony_ci  return cfi;
192da0c48c4Sopenharmony_ci}
193da0c48c4Sopenharmony_ci
194da0c48c4Sopenharmony_ci/* Search the phdrs for PT_GNU_EH_FRAME.  */
195da0c48c4Sopenharmony_cistatic Dwarf_CFI *
196da0c48c4Sopenharmony_cigetcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
197da0c48c4Sopenharmony_ci{
198da0c48c4Sopenharmony_ci  size_t phnum;
199da0c48c4Sopenharmony_ci  if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
200da0c48c4Sopenharmony_ci    return NULL;
201da0c48c4Sopenharmony_ci
202da0c48c4Sopenharmony_ci  for (size_t i = 0; i < phnum; ++i)
203da0c48c4Sopenharmony_ci    {
204da0c48c4Sopenharmony_ci      GElf_Phdr phdr_mem;
205da0c48c4Sopenharmony_ci      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
206da0c48c4Sopenharmony_ci      if (unlikely (phdr == NULL))
207da0c48c4Sopenharmony_ci	return NULL;
208da0c48c4Sopenharmony_ci      if (phdr->p_type == PT_GNU_EH_FRAME)
209da0c48c4Sopenharmony_ci	return getcfi_gnu_eh_frame (elf, ehdr, phdr);
210da0c48c4Sopenharmony_ci    }
211da0c48c4Sopenharmony_ci
212da0c48c4Sopenharmony_ci  __libdw_seterrno (DWARF_E_NO_DWARF);
213da0c48c4Sopenharmony_ci  return NULL;
214da0c48c4Sopenharmony_ci}
215da0c48c4Sopenharmony_ci
216da0c48c4Sopenharmony_cistatic Dwarf_CFI *
217da0c48c4Sopenharmony_cigetcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
218da0c48c4Sopenharmony_ci		     Elf_Scn *scn, GElf_Shdr *shdr,
219da0c48c4Sopenharmony_ci		     Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr)
220da0c48c4Sopenharmony_ci{
221da0c48c4Sopenharmony_ci  Elf_Data *data = elf_rawdata (scn, NULL);
222da0c48c4Sopenharmony_ci  if (data == NULL || data->d_buf == NULL)
223da0c48c4Sopenharmony_ci    {
224da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_ELF);
225da0c48c4Sopenharmony_ci      return NULL;
226da0c48c4Sopenharmony_ci    }
227da0c48c4Sopenharmony_ci  Dwarf_CFI *cfi = allocate_cfi (elf, ehdr, shdr->sh_addr);
228da0c48c4Sopenharmony_ci  if (cfi != NULL)
229da0c48c4Sopenharmony_ci    {
230da0c48c4Sopenharmony_ci      cfi->data = (Elf_Data_Scn *) data;
231da0c48c4Sopenharmony_ci      if (hdr_scn != NULL)
232da0c48c4Sopenharmony_ci	{
233da0c48c4Sopenharmony_ci	  Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
234da0c48c4Sopenharmony_ci	  if (hdr_data != NULL && hdr_data->d_buf != NULL)
235da0c48c4Sopenharmony_ci	    {
236da0c48c4Sopenharmony_ci	      size_t vsize, dmax;
237da0c48c4Sopenharmony_ci	      GElf_Addr eh_frame_vaddr;
238da0c48c4Sopenharmony_ci	      cfi->search_table_vaddr = hdr_vaddr;
239da0c48c4Sopenharmony_ci	      cfi->search_table
240da0c48c4Sopenharmony_ci		= parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size,
241da0c48c4Sopenharmony_ci				      hdr_vaddr, ehdr, &eh_frame_vaddr,
242da0c48c4Sopenharmony_ci				      &cfi->search_table_entries,
243da0c48c4Sopenharmony_ci				      &cfi->search_table_encoding);
244da0c48c4Sopenharmony_ci	      cfi->search_table_len = hdr_data->d_size;
245da0c48c4Sopenharmony_ci
246da0c48c4Sopenharmony_ci	      /* Make sure there is enough room for the entries in the table,
247da0c48c4Sopenharmony_ci		 each entry consists of 2 encoded values.  */
248da0c48c4Sopenharmony_ci	      vsize = encoded_value_size (hdr_data, ehdr->e_ident,
249da0c48c4Sopenharmony_ci					  cfi->search_table_encoding, NULL);
250da0c48c4Sopenharmony_ci	      dmax = hdr_data->d_size - (cfi->search_table
251da0c48c4Sopenharmony_ci					 - (const uint8_t *) hdr_data->d_buf);
252da0c48c4Sopenharmony_ci	      if (unlikely (cfi->search_table == (void *) -1l
253da0c48c4Sopenharmony_ci			    || vsize == 0
254da0c48c4Sopenharmony_ci			    || cfi->search_table_entries > (dmax / vsize) / 2))
255da0c48c4Sopenharmony_ci		{
256da0c48c4Sopenharmony_ci		  free (cfi);
257da0c48c4Sopenharmony_ci		  /* XXX might be read error or corrupt phdr */
258da0c48c4Sopenharmony_ci		  __libdw_seterrno (DWARF_E_INVALID_CFI);
259da0c48c4Sopenharmony_ci		  return NULL;
260da0c48c4Sopenharmony_ci		}
261da0c48c4Sopenharmony_ci
262da0c48c4Sopenharmony_ci	      /* Sanity check.  */
263da0c48c4Sopenharmony_ci	      if (unlikely (eh_frame_vaddr != shdr->sh_addr))
264da0c48c4Sopenharmony_ci		cfi->search_table = NULL;
265da0c48c4Sopenharmony_ci	    }
266da0c48c4Sopenharmony_ci	}
267da0c48c4Sopenharmony_ci    }
268da0c48c4Sopenharmony_ci  return cfi;
269da0c48c4Sopenharmony_ci}
270da0c48c4Sopenharmony_ci
271da0c48c4Sopenharmony_ci/* Search for the sections named ".eh_frame" and ".eh_frame_hdr".  */
272da0c48c4Sopenharmony_cistatic Dwarf_CFI *
273da0c48c4Sopenharmony_cigetcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
274da0c48c4Sopenharmony_ci{
275da0c48c4Sopenharmony_ci  size_t shstrndx;
276da0c48c4Sopenharmony_ci  if (elf_getshdrstrndx (elf, &shstrndx) != 0)
277da0c48c4Sopenharmony_ci    {
278da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
279da0c48c4Sopenharmony_ci      return NULL;
280da0c48c4Sopenharmony_ci    }
281da0c48c4Sopenharmony_ci
282da0c48c4Sopenharmony_ci  if (shstrndx != 0)
283da0c48c4Sopenharmony_ci    {
284da0c48c4Sopenharmony_ci      Elf_Scn *hdr_scn = NULL;
285da0c48c4Sopenharmony_ci      GElf_Addr hdr_vaddr = 0;
286da0c48c4Sopenharmony_ci      Elf_Scn *scn = NULL;
287da0c48c4Sopenharmony_ci      while ((scn = elf_nextscn (elf, scn)) != NULL)
288da0c48c4Sopenharmony_ci	{
289da0c48c4Sopenharmony_ci	  GElf_Shdr shdr_mem;
290da0c48c4Sopenharmony_ci	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
291da0c48c4Sopenharmony_ci	  if (shdr == NULL)
292da0c48c4Sopenharmony_ci	    continue;
293da0c48c4Sopenharmony_ci	  const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
294da0c48c4Sopenharmony_ci	  if (name == NULL)
295da0c48c4Sopenharmony_ci	    continue;
296da0c48c4Sopenharmony_ci	  if (!strcmp (name, ".eh_frame_hdr"))
297da0c48c4Sopenharmony_ci	    {
298da0c48c4Sopenharmony_ci	      hdr_scn = scn;
299da0c48c4Sopenharmony_ci	      hdr_vaddr = shdr->sh_addr;
300da0c48c4Sopenharmony_ci	    }
301da0c48c4Sopenharmony_ci	  else if (!strcmp (name, ".eh_frame"))
302da0c48c4Sopenharmony_ci	    {
303da0c48c4Sopenharmony_ci	      if (shdr->sh_type != SHT_NOBITS)
304da0c48c4Sopenharmony_ci		return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
305da0c48c4Sopenharmony_ci					    hdr_scn, hdr_vaddr);
306da0c48c4Sopenharmony_ci	      else
307da0c48c4Sopenharmony_ci		return NULL;
308da0c48c4Sopenharmony_ci	    }
309da0c48c4Sopenharmony_ci	}
310da0c48c4Sopenharmony_ci    }
311da0c48c4Sopenharmony_ci
312da0c48c4Sopenharmony_ci  return (void *) -1l;
313da0c48c4Sopenharmony_ci}
314da0c48c4Sopenharmony_ci
315da0c48c4Sopenharmony_ciDwarf_CFI *
316da0c48c4Sopenharmony_cidwarf_getcfi_elf (Elf *elf)
317da0c48c4Sopenharmony_ci{
318da0c48c4Sopenharmony_ci  if (elf_kind (elf) != ELF_K_ELF)
319da0c48c4Sopenharmony_ci    {
320da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_NOELF);
321da0c48c4Sopenharmony_ci      return NULL;
322da0c48c4Sopenharmony_ci    }
323da0c48c4Sopenharmony_ci
324da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr_mem;
325da0c48c4Sopenharmony_ci  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
326da0c48c4Sopenharmony_ci  if (unlikely (ehdr == NULL))
327da0c48c4Sopenharmony_ci    {
328da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_ELF);
329da0c48c4Sopenharmony_ci      return NULL;
330da0c48c4Sopenharmony_ci    }
331da0c48c4Sopenharmony_ci
332da0c48c4Sopenharmony_ci  Dwarf_CFI *result = getcfi_shdr (elf, ehdr);
333da0c48c4Sopenharmony_ci  if (result == (void *) -1l)
334da0c48c4Sopenharmony_ci    result = getcfi_phdr (elf, ehdr);
335da0c48c4Sopenharmony_ci
336da0c48c4Sopenharmony_ci  return result;
337da0c48c4Sopenharmony_ci}
338da0c48c4Sopenharmony_ciINTDEF (dwarf_getcfi_elf)
339