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