xref: /aosp_15_r20/external/elfutils/libdw/cie.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* CIE reading.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2009-2010 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 "cfi.h"
34*7304104dSAndroid Build Coastguard Worker #include "encoded-value.h"
35*7304104dSAndroid Build Coastguard Worker #include <assert.h>
36*7304104dSAndroid Build Coastguard Worker #include <search.h>
37*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
38*7304104dSAndroid Build Coastguard Worker 
39*7304104dSAndroid Build Coastguard Worker 
40*7304104dSAndroid Build Coastguard Worker static int
compare_cie(const void * a,const void * b)41*7304104dSAndroid Build Coastguard Worker compare_cie (const void *a, const void *b)
42*7304104dSAndroid Build Coastguard Worker {
43*7304104dSAndroid Build Coastguard Worker   const struct dwarf_cie *cie1 = a;
44*7304104dSAndroid Build Coastguard Worker   const struct dwarf_cie *cie2 = b;
45*7304104dSAndroid Build Coastguard Worker   if (cie1->offset < cie2->offset)
46*7304104dSAndroid Build Coastguard Worker     return -1;
47*7304104dSAndroid Build Coastguard Worker   if (cie1->offset > cie2->offset)
48*7304104dSAndroid Build Coastguard Worker     return 1;
49*7304104dSAndroid Build Coastguard Worker   return 0;
50*7304104dSAndroid Build Coastguard Worker }
51*7304104dSAndroid Build Coastguard Worker 
52*7304104dSAndroid Build Coastguard Worker /* There is no CIE at OFFSET in the tree.  Add it.  */
53*7304104dSAndroid Build Coastguard Worker static struct dwarf_cie *
intern_new_cie(Dwarf_CFI * cache,Dwarf_Off offset,const Dwarf_CIE * info)54*7304104dSAndroid Build Coastguard Worker intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
55*7304104dSAndroid Build Coastguard Worker {
56*7304104dSAndroid Build Coastguard Worker   struct dwarf_cie *cie = malloc (sizeof (struct dwarf_cie));
57*7304104dSAndroid Build Coastguard Worker   if (cie == NULL)
58*7304104dSAndroid Build Coastguard Worker     {
59*7304104dSAndroid Build Coastguard Worker       __libdw_seterrno (DWARF_E_NOMEM);
60*7304104dSAndroid Build Coastguard Worker       return NULL;
61*7304104dSAndroid Build Coastguard Worker     }
62*7304104dSAndroid Build Coastguard Worker 
63*7304104dSAndroid Build Coastguard Worker   cie->offset = offset;
64*7304104dSAndroid Build Coastguard Worker   cie->code_alignment_factor = info->code_alignment_factor;
65*7304104dSAndroid Build Coastguard Worker   cie->data_alignment_factor = info->data_alignment_factor;
66*7304104dSAndroid Build Coastguard Worker   cie->return_address_register = info->return_address_register;
67*7304104dSAndroid Build Coastguard Worker 
68*7304104dSAndroid Build Coastguard Worker   cie->fde_augmentation_data_size = 0;
69*7304104dSAndroid Build Coastguard Worker   cie->sized_augmentation_data = false;
70*7304104dSAndroid Build Coastguard Worker   cie->signal_frame = false;
71*7304104dSAndroid Build Coastguard Worker 
72*7304104dSAndroid Build Coastguard Worker   cie->fde_encoding = DW_EH_PE_absptr;
73*7304104dSAndroid Build Coastguard Worker   cie->lsda_encoding = DW_EH_PE_omit;
74*7304104dSAndroid Build Coastguard Worker 
75*7304104dSAndroid Build Coastguard Worker   /* Grok the augmentation string and its data.  */
76*7304104dSAndroid Build Coastguard Worker   const uint8_t *data = info->augmentation_data;
77*7304104dSAndroid Build Coastguard Worker   for (const char *ap = info->augmentation; *ap != '\0'; ++ap)
78*7304104dSAndroid Build Coastguard Worker     {
79*7304104dSAndroid Build Coastguard Worker       uint8_t encoding;
80*7304104dSAndroid Build Coastguard Worker       switch (*ap)
81*7304104dSAndroid Build Coastguard Worker 	{
82*7304104dSAndroid Build Coastguard Worker 	case 'z':
83*7304104dSAndroid Build Coastguard Worker 	  cie->sized_augmentation_data = true;
84*7304104dSAndroid Build Coastguard Worker 	  continue;
85*7304104dSAndroid Build Coastguard Worker 
86*7304104dSAndroid Build Coastguard Worker 	case 'S':
87*7304104dSAndroid Build Coastguard Worker 	  cie->signal_frame = true;
88*7304104dSAndroid Build Coastguard Worker 	  continue;
89*7304104dSAndroid Build Coastguard Worker 
90*7304104dSAndroid Build Coastguard Worker 	case 'L':		/* LSDA pointer encoding byte.  */
91*7304104dSAndroid Build Coastguard Worker 	  cie->lsda_encoding = *data++;
92*7304104dSAndroid Build Coastguard Worker 	  if (!cie->sized_augmentation_data)
93*7304104dSAndroid Build Coastguard Worker 	    cie->fde_augmentation_data_size
94*7304104dSAndroid Build Coastguard Worker 	      += encoded_value_size (&cache->data->d, cache->e_ident,
95*7304104dSAndroid Build Coastguard Worker 				     cie->lsda_encoding, NULL);
96*7304104dSAndroid Build Coastguard Worker 	  continue;
97*7304104dSAndroid Build Coastguard Worker 
98*7304104dSAndroid Build Coastguard Worker 	case 'R':		/* FDE address encoding byte.  */
99*7304104dSAndroid Build Coastguard Worker 	  cie->fde_encoding = *data++;
100*7304104dSAndroid Build Coastguard Worker 	  continue;
101*7304104dSAndroid Build Coastguard Worker 
102*7304104dSAndroid Build Coastguard Worker 	case 'P':		/* Skip personality routine.  */
103*7304104dSAndroid Build Coastguard Worker 	  encoding = *data++;
104*7304104dSAndroid Build Coastguard Worker 	  data += encoded_value_size (&cache->data->d, cache->e_ident,
105*7304104dSAndroid Build Coastguard Worker 				      encoding, data);
106*7304104dSAndroid Build Coastguard Worker 	  continue;
107*7304104dSAndroid Build Coastguard Worker 
108*7304104dSAndroid Build Coastguard Worker 	default:
109*7304104dSAndroid Build Coastguard Worker 	  /* Unknown augmentation string.  If we have 'z' we can ignore it,
110*7304104dSAndroid Build Coastguard Worker 	     otherwise we must bail out.  */
111*7304104dSAndroid Build Coastguard Worker 	  if (cie->sized_augmentation_data)
112*7304104dSAndroid Build Coastguard Worker 	    continue;
113*7304104dSAndroid Build Coastguard Worker 	}
114*7304104dSAndroid Build Coastguard Worker       /* We only get here when we need to bail out.  */
115*7304104dSAndroid Build Coastguard Worker       break;
116*7304104dSAndroid Build Coastguard Worker     }
117*7304104dSAndroid Build Coastguard Worker 
118*7304104dSAndroid Build Coastguard Worker   if ((cie->fde_encoding & 0x0f) == DW_EH_PE_absptr)
119*7304104dSAndroid Build Coastguard Worker     {
120*7304104dSAndroid Build Coastguard Worker       /* Canonicalize encoding to a specific size.  */
121*7304104dSAndroid Build Coastguard Worker       assert (DW_EH_PE_absptr == 0);
122*7304104dSAndroid Build Coastguard Worker 
123*7304104dSAndroid Build Coastguard Worker       /* XXX should get from dwarf_next_cfi with v4 header.  */
124*7304104dSAndroid Build Coastguard Worker       uint_fast8_t address_size
125*7304104dSAndroid Build Coastguard Worker 	= cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
126*7304104dSAndroid Build Coastguard Worker       switch (address_size)
127*7304104dSAndroid Build Coastguard Worker 	{
128*7304104dSAndroid Build Coastguard Worker 	case 8:
129*7304104dSAndroid Build Coastguard Worker 	  cie->fde_encoding |= DW_EH_PE_udata8;
130*7304104dSAndroid Build Coastguard Worker 	  break;
131*7304104dSAndroid Build Coastguard Worker 	case 4:
132*7304104dSAndroid Build Coastguard Worker 	  cie->fde_encoding |= DW_EH_PE_udata4;
133*7304104dSAndroid Build Coastguard Worker 	  break;
134*7304104dSAndroid Build Coastguard Worker 	default:
135*7304104dSAndroid Build Coastguard Worker 	  free (cie);
136*7304104dSAndroid Build Coastguard Worker 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
137*7304104dSAndroid Build Coastguard Worker 	  return NULL;
138*7304104dSAndroid Build Coastguard Worker 	}
139*7304104dSAndroid Build Coastguard Worker     }
140*7304104dSAndroid Build Coastguard Worker 
141*7304104dSAndroid Build Coastguard Worker   /* Save the initial instructions to be played out into initial state.  */
142*7304104dSAndroid Build Coastguard Worker   cie->initial_instructions = info->initial_instructions;
143*7304104dSAndroid Build Coastguard Worker   cie->initial_instructions_end = info->initial_instructions_end;
144*7304104dSAndroid Build Coastguard Worker   cie->initial_state = NULL;
145*7304104dSAndroid Build Coastguard Worker 
146*7304104dSAndroid Build Coastguard Worker   /* Add the new entry to the search tree.  */
147*7304104dSAndroid Build Coastguard Worker   if (tsearch (cie, &cache->cie_tree, &compare_cie) == NULL)
148*7304104dSAndroid Build Coastguard Worker     {
149*7304104dSAndroid Build Coastguard Worker       free (cie);
150*7304104dSAndroid Build Coastguard Worker       __libdw_seterrno (DWARF_E_NOMEM);
151*7304104dSAndroid Build Coastguard Worker       return NULL;
152*7304104dSAndroid Build Coastguard Worker     }
153*7304104dSAndroid Build Coastguard Worker 
154*7304104dSAndroid Build Coastguard Worker   return cie;
155*7304104dSAndroid Build Coastguard Worker }
156*7304104dSAndroid Build Coastguard Worker 
157*7304104dSAndroid Build Coastguard Worker /* Look up a CIE_pointer for random access.  */
158*7304104dSAndroid Build Coastguard Worker struct dwarf_cie *
159*7304104dSAndroid Build Coastguard Worker internal_function
__libdw_find_cie(Dwarf_CFI * cache,Dwarf_Off offset)160*7304104dSAndroid Build Coastguard Worker __libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset)
161*7304104dSAndroid Build Coastguard Worker {
162*7304104dSAndroid Build Coastguard Worker   const struct dwarf_cie cie_key = { .offset = offset };
163*7304104dSAndroid Build Coastguard Worker   struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie);
164*7304104dSAndroid Build Coastguard Worker   if (found != NULL)
165*7304104dSAndroid Build Coastguard Worker     return *found;
166*7304104dSAndroid Build Coastguard Worker 
167*7304104dSAndroid Build Coastguard Worker   /* We have not read this CIE yet.  Go find it.  */
168*7304104dSAndroid Build Coastguard Worker   Dwarf_Off next_offset = offset;
169*7304104dSAndroid Build Coastguard Worker   Dwarf_CFI_Entry entry;
170*7304104dSAndroid Build Coastguard Worker   int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
171*7304104dSAndroid Build Coastguard Worker 				       &cache->data->d, CFI_IS_EH (cache),
172*7304104dSAndroid Build Coastguard Worker 				       offset, &next_offset, &entry);
173*7304104dSAndroid Build Coastguard Worker   if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64)
174*7304104dSAndroid Build Coastguard Worker     {
175*7304104dSAndroid Build Coastguard Worker       __libdw_seterrno (DWARF_E_INVALID_DWARF);
176*7304104dSAndroid Build Coastguard Worker       return NULL;
177*7304104dSAndroid Build Coastguard Worker     }
178*7304104dSAndroid Build Coastguard Worker 
179*7304104dSAndroid Build Coastguard Worker   /* If this happened to be what we would have read next, notice it.  */
180*7304104dSAndroid Build Coastguard Worker   if (cache->next_offset == offset)
181*7304104dSAndroid Build Coastguard Worker     cache->next_offset = next_offset;
182*7304104dSAndroid Build Coastguard Worker 
183*7304104dSAndroid Build Coastguard Worker   return intern_new_cie (cache, offset, &entry.cie);
184*7304104dSAndroid Build Coastguard Worker }
185*7304104dSAndroid Build Coastguard Worker 
186*7304104dSAndroid Build Coastguard Worker /* Enter a CIE encountered while reading through for FDEs.  */
187*7304104dSAndroid Build Coastguard Worker void
188*7304104dSAndroid Build Coastguard Worker internal_function
__libdw_intern_cie(Dwarf_CFI * cache,Dwarf_Off offset,const Dwarf_CIE * info)189*7304104dSAndroid Build Coastguard Worker __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
190*7304104dSAndroid Build Coastguard Worker {
191*7304104dSAndroid Build Coastguard Worker   const struct dwarf_cie cie_key = { .offset = offset };
192*7304104dSAndroid Build Coastguard Worker   struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie);
193*7304104dSAndroid Build Coastguard Worker   if (found == NULL)
194*7304104dSAndroid Build Coastguard Worker     /* We have not read this CIE yet.  Enter it.  */
195*7304104dSAndroid Build Coastguard Worker     (void) intern_new_cie (cache, offset, info);
196*7304104dSAndroid Build Coastguard Worker }
197