Coverage Report

Created: 2025-07-18 06:06

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