elf-sframe.c revision 1.1.1.2 1 1.1 christos /* .sframe section processing.
2 1.1.1.2 christos Copyright (C) 2022-2025 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of BFD, the Binary File Descriptor library.
5 1.1 christos
6 1.1 christos This program is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3 of the License, or
9 1.1 christos (at your option) any later version.
10 1.1 christos
11 1.1 christos This program is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 christos GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program; if not, write to the Free Software
18 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 1.1 christos MA 02110-1301, USA. */
20 1.1 christos
21 1.1 christos #include "sysdep.h"
22 1.1 christos #include "bfd.h"
23 1.1 christos #include "libbfd.h"
24 1.1 christos #include "elf-bfd.h"
25 1.1 christos #include "sframe-api.h"
26 1.1.1.2 christos #include "sframe-internal.h"
27 1.1 christos
28 1.1 christos /* Return TRUE if the function has been marked for deletion during the linking
29 1.1 christos process. */
30 1.1 christos
31 1.1 christos static bool
32 1.1 christos sframe_decoder_func_deleted_p (struct sframe_dec_info *sfd_info,
33 1.1 christos unsigned int func_idx)
34 1.1 christos {
35 1.1 christos if (func_idx < sfd_info->sfd_fde_count)
36 1.1 christos return sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p;
37 1.1 christos
38 1.1 christos return false;
39 1.1 christos }
40 1.1 christos
41 1.1 christos /* Mark the function in the decoder info for deletion. */
42 1.1 christos
43 1.1 christos static void
44 1.1 christos sframe_decoder_mark_func_deleted (struct sframe_dec_info *sfd_info,
45 1.1 christos unsigned int func_idx)
46 1.1 christos {
47 1.1 christos if (func_idx < sfd_info->sfd_fde_count)
48 1.1 christos sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p = true;
49 1.1 christos }
50 1.1 christos
51 1.1 christos /* Get the relocation offset from the decoder info for the given function. */
52 1.1 christos
53 1.1 christos static unsigned int
54 1.1 christos sframe_decoder_get_func_r_offset (struct sframe_dec_info *sfd_info,
55 1.1 christos unsigned int func_idx)
56 1.1 christos {
57 1.1 christos BFD_ASSERT (func_idx < sfd_info->sfd_fde_count);
58 1.1 christos unsigned int func_r_offset
59 1.1 christos = sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset;
60 1.1 christos /* There must have been a reloc. */
61 1.1 christos BFD_ASSERT (func_r_offset);
62 1.1 christos return func_r_offset;
63 1.1 christos }
64 1.1 christos
65 1.1 christos /* Bookkeep the function relocation offset in the decoder info. */
66 1.1 christos
67 1.1 christos static void
68 1.1 christos sframe_decoder_set_func_r_offset (struct sframe_dec_info *sfd_info,
69 1.1 christos unsigned int func_idx,
70 1.1 christos unsigned int r_offset)
71 1.1 christos {
72 1.1 christos if (func_idx < sfd_info->sfd_fde_count)
73 1.1 christos sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset = r_offset;
74 1.1 christos }
75 1.1 christos
76 1.1 christos /* Get the relocation index in the elf_reloc_cookie for the function. */
77 1.1 christos
78 1.1 christos static unsigned int
79 1.1 christos sframe_decoder_get_func_reloc_index (struct sframe_dec_info *sfd_info,
80 1.1 christos unsigned int func_idx)
81 1.1 christos {
82 1.1 christos BFD_ASSERT (func_idx < sfd_info->sfd_fde_count);
83 1.1 christos return sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index;
84 1.1 christos }
85 1.1 christos
86 1.1 christos /* Bookkeep the relocation index in the elf_reloc_cookie for the function. */
87 1.1 christos
88 1.1 christos static void
89 1.1 christos sframe_decoder_set_func_reloc_index (struct sframe_dec_info *sfd_info,
90 1.1 christos unsigned int func_idx,
91 1.1 christos unsigned int reloc_index)
92 1.1 christos {
93 1.1 christos if (func_idx < sfd_info->sfd_fde_count)
94 1.1 christos sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index = reloc_index;
95 1.1 christos }
96 1.1 christos
97 1.1 christos /* Initialize the set of additional information in CFD_INFO,
98 1.1 christos needed for linking SEC. Returns TRUE if setup is done successfully. */
99 1.1 christos
100 1.1 christos static bool
101 1.1.1.2 christos sframe_decoder_init_func_bfdinfo (bfd *abfd,
102 1.1.1.2 christos const asection *sec,
103 1.1 christos struct sframe_dec_info *sfd_info,
104 1.1.1.2 christos const struct elf_reloc_cookie *cookie)
105 1.1 christos {
106 1.1 christos unsigned int fde_count;
107 1.1 christos unsigned int func_bfdinfo_size, i;
108 1.1.1.2 christos const Elf_Internal_Rela *rel;
109 1.1 christos
110 1.1 christos fde_count = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx);
111 1.1 christos sfd_info->sfd_fde_count = fde_count;
112 1.1 christos
113 1.1 christos /* Allocate and clear the memory. */
114 1.1 christos func_bfdinfo_size = (sizeof (struct sframe_func_bfdinfo)) * fde_count;
115 1.1.1.2 christos sfd_info->sfd_func_bfdinfo = bfd_zalloc (abfd, func_bfdinfo_size);
116 1.1 christos if (sfd_info->sfd_func_bfdinfo == NULL)
117 1.1 christos return false;
118 1.1 christos
119 1.1 christos /* For linker generated .sframe sections, we have no relocs. Skip. */
120 1.1 christos if ((sec->flags & SEC_LINKER_CREATED) && cookie->rels == NULL)
121 1.1 christos return true;
122 1.1 christos
123 1.1.1.2 christos rel = cookie->rels;
124 1.1 christos for (i = 0; i < fde_count; i++)
125 1.1 christos {
126 1.1 christos /* Bookkeep the relocation offset and relocation index of each function
127 1.1 christos for later use. */
128 1.1.1.2 christos sframe_decoder_set_func_r_offset (sfd_info, i, rel->r_offset);
129 1.1.1.2 christos sframe_decoder_set_func_reloc_index (sfd_info, i, i);
130 1.1 christos
131 1.1.1.2 christos rel++;
132 1.1 christos }
133 1.1.1.2 christos
134 1.1.1.2 christos /* If there are more relocation entries, they must be R_*_NONE which
135 1.1.1.2 christos may be generated from relocations against discarded sections by
136 1.1.1.2 christos ld -r. */
137 1.1.1.2 christos for (; rel < cookie->relend; rel++)
138 1.1.1.2 christos if (rel->r_info != 0)
139 1.1.1.2 christos break;
140 1.1.1.2 christos BFD_ASSERT (rel == cookie->relend);
141 1.1 christos
142 1.1 christos return true;
143 1.1 christos }
144 1.1 christos
145 1.1 christos /* Read the value from CONTENTS at the specified OFFSET for the given ABFD. */
146 1.1 christos
147 1.1 christos static bfd_vma
148 1.1 christos sframe_read_value (bfd *abfd, bfd_byte *contents, unsigned int offset,
149 1.1 christos unsigned int width)
150 1.1 christos {
151 1.1 christos BFD_ASSERT (contents && offset);
152 1.1 christos /* Supporting the usecase of reading only the 4-byte relocated
153 1.1 christos value (signed offset for func start addr) for now. */
154 1.1 christos BFD_ASSERT (width == 4);
155 1.1 christos /* FIXME endianness ?? */
156 1.1 christos unsigned char *buf = contents + offset;
157 1.1 christos bfd_vma value = bfd_get_signed_32 (abfd, buf);
158 1.1 christos return value;
159 1.1 christos }
160 1.1 christos
161 1.1 christos /* Return true if there is at least one non-empty .sframe section in
162 1.1 christos input files. Can only be called after ld has mapped input to
163 1.1 christos output sections, and before sections are stripped. */
164 1.1 christos
165 1.1 christos bool
166 1.1 christos _bfd_elf_sframe_present (struct bfd_link_info *info)
167 1.1 christos {
168 1.1 christos asection *sframe = bfd_get_section_by_name (info->output_bfd, ".sframe");
169 1.1 christos
170 1.1 christos if (sframe == NULL)
171 1.1 christos return false;
172 1.1 christos
173 1.1 christos /* Count only sections which have at least a single FDE. */
174 1.1 christos for (sframe = sframe->map_head.s; sframe != NULL; sframe = sframe->map_head.s)
175 1.1 christos /* Note that this may become an approximate check in the future when
176 1.1 christos some ABI/arch begin to use the sfh_auxhdr_len. When sfh_auxhdr_len has
177 1.1 christos non-zero value, it will need to be accounted for in the calculation of
178 1.1 christos the SFrame header size. */
179 1.1 christos if (sframe->size > sizeof (sframe_header))
180 1.1 christos return true;
181 1.1 christos return false;
182 1.1 christos }
183 1.1 christos
184 1.1 christos /* Try to parse .sframe section SEC, which belongs to ABFD. Store the
185 1.1 christos information in the section's sec_info field on success. COOKIE
186 1.1 christos describes the relocations in SEC.
187 1.1 christos
188 1.1 christos Returns TRUE if success, FALSE if any error or failure. */
189 1.1 christos
190 1.1 christos bool
191 1.1 christos _bfd_elf_parse_sframe (bfd *abfd,
192 1.1 christos struct bfd_link_info *info ATTRIBUTE_UNUSED,
193 1.1 christos asection *sec, struct elf_reloc_cookie *cookie)
194 1.1 christos {
195 1.1 christos bfd_byte *sfbuf = NULL;
196 1.1 christos struct sframe_dec_info *sfd_info;
197 1.1 christos sframe_decoder_ctx *sfd_ctx;
198 1.1 christos bfd_size_type sf_size;
199 1.1 christos int decerr = 0;
200 1.1 christos
201 1.1.1.2 christos /* Prior versions of assembler and ld were generating SFrame sections with
202 1.1.1.2 christos section type SHT_PROGBITS. Issue an error for lack of support for such
203 1.1.1.2 christos objects now. Even if section size is zero, a valid section type is
204 1.1.1.2 christos expected. */
205 1.1.1.2 christos if (elf_section_type (sec) != SHT_GNU_SFRAME)
206 1.1.1.2 christos {
207 1.1.1.2 christos _bfd_error_handler
208 1.1.1.2 christos (_("error in %pB(%pA); unexpected SFrame section type"),
209 1.1.1.2 christos abfd, sec);
210 1.1.1.2 christos return false;
211 1.1.1.2 christos }
212 1.1.1.2 christos
213 1.1 christos if (sec->size == 0
214 1.1 christos || (sec->flags & SEC_HAS_CONTENTS) == 0
215 1.1 christos || sec->sec_info_type != SEC_INFO_TYPE_NONE)
216 1.1 christos {
217 1.1 christos /* This file does not contain .sframe information. */
218 1.1 christos return false;
219 1.1 christos }
220 1.1 christos
221 1.1 christos if (bfd_is_abs_section (sec->output_section))
222 1.1 christos {
223 1.1 christos /* At least one of the sections is being discarded from the
224 1.1 christos link, so we should just ignore them. */
225 1.1 christos return false;
226 1.1 christos }
227 1.1 christos
228 1.1 christos /* Read the SFrame stack trace information from abfd. */
229 1.1.1.2 christos if (!_bfd_elf_mmap_section_contents (abfd, sec, &sfbuf))
230 1.1 christos goto fail_no_free;
231 1.1 christos
232 1.1 christos /* Decode the buffer and keep decoded contents for later use.
233 1.1 christos Relocations are performed later, but are such that the section's
234 1.1 christos size is unaffected. */
235 1.1.1.2 christos sfd_info = bfd_zalloc (abfd, sizeof (*sfd_info));
236 1.1 christos sf_size = sec->size;
237 1.1 christos
238 1.1 christos sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr);
239 1.1.1.2 christos sfd_info->sfd_state = SFRAME_SEC_DECODED;
240 1.1 christos sfd_ctx = sfd_info->sfd_ctx;
241 1.1 christos if (!sfd_ctx)
242 1.1 christos /* Free'ing up any memory held by decoder context is done by
243 1.1 christos sframe_decode in case of error. */
244 1.1 christos goto fail_no_free;
245 1.1 christos
246 1.1.1.2 christos if (!sframe_decoder_init_func_bfdinfo (abfd, sec, sfd_info, cookie))
247 1.1 christos {
248 1.1 christos sframe_decoder_free (&sfd_ctx);
249 1.1 christos goto fail_no_free;
250 1.1 christos }
251 1.1 christos
252 1.1 christos elf_section_data (sec)->sec_info = sfd_info;
253 1.1 christos sec->sec_info_type = SEC_INFO_TYPE_SFRAME;
254 1.1 christos
255 1.1 christos goto success;
256 1.1 christos
257 1.1 christos fail_no_free:
258 1.1 christos _bfd_error_handler
259 1.1 christos (_("error in %pB(%pA); no .sframe will be created"),
260 1.1 christos abfd, sec);
261 1.1 christos return false;
262 1.1 christos success:
263 1.1.1.2 christos _bfd_elf_munmap_section_contents (sec, sfbuf);
264 1.1 christos return true;
265 1.1 christos }
266 1.1 christos
267 1.1 christos /* This function is called for each input file before the .sframe section
268 1.1 christos is relocated. It marks the SFrame FDE for the discarded functions for
269 1.1 christos deletion.
270 1.1 christos
271 1.1 christos The function returns TRUE iff any entries have been deleted. */
272 1.1 christos
273 1.1 christos bool
274 1.1 christos _bfd_elf_discard_section_sframe
275 1.1 christos (asection *sec,
276 1.1 christos bool (*reloc_symbol_deleted_p) (bfd_vma, void *),
277 1.1 christos struct elf_reloc_cookie *cookie)
278 1.1 christos {
279 1.1 christos bool changed;
280 1.1 christos bool keep;
281 1.1 christos unsigned int i;
282 1.1 christos unsigned int func_desc_offset;
283 1.1 christos unsigned int num_fidx;
284 1.1 christos struct sframe_dec_info *sfd_info;
285 1.1 christos
286 1.1 christos changed = false;
287 1.1 christos /* FIXME - if relocatable link and changed = true, how does the final
288 1.1 christos .rela.sframe get updated ?. */
289 1.1 christos keep = false;
290 1.1 christos
291 1.1 christos sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
292 1.1 christos
293 1.1 christos /* Skip checking for the linker created .sframe sections
294 1.1 christos (for PLT sections). */
295 1.1 christos if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL)
296 1.1 christos {
297 1.1 christos num_fidx = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx);
298 1.1 christos for (i = 0; i < num_fidx; i++)
299 1.1 christos {
300 1.1 christos func_desc_offset = sframe_decoder_get_func_r_offset (sfd_info, i);
301 1.1 christos
302 1.1 christos cookie->rel = cookie->rels
303 1.1 christos + sframe_decoder_get_func_reloc_index (sfd_info, i);
304 1.1 christos keep = !(*reloc_symbol_deleted_p) (func_desc_offset, cookie);
305 1.1 christos
306 1.1 christos if (!keep)
307 1.1 christos {
308 1.1 christos sframe_decoder_mark_func_deleted (sfd_info, i);
309 1.1 christos changed = true;
310 1.1 christos }
311 1.1 christos }
312 1.1 christos }
313 1.1 christos return changed;
314 1.1 christos }
315 1.1 christos
316 1.1 christos /* Update the reference to the output .sframe section in the output ELF
317 1.1 christos BFD ABFD. Returns true if no error. */
318 1.1 christos
319 1.1 christos bool
320 1.1.1.2 christos _bfd_elf_set_section_sframe (bfd *abfd, struct bfd_link_info *info)
321 1.1 christos {
322 1.1 christos asection *cfsec;
323 1.1 christos
324 1.1 christos cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe");
325 1.1 christos if (!cfsec)
326 1.1 christos return false;
327 1.1 christos
328 1.1.1.2 christos elf_section_type (cfsec) = SHT_GNU_SFRAME;
329 1.1 christos elf_sframe (abfd) = cfsec;
330 1.1 christos
331 1.1 christos return true;
332 1.1 christos }
333 1.1 christos
334 1.1 christos /* Merge .sframe section SEC. This is called with the relocated
335 1.1 christos CONTENTS. */
336 1.1 christos
337 1.1 christos bool
338 1.1 christos _bfd_elf_merge_section_sframe (bfd *abfd,
339 1.1 christos struct bfd_link_info *info,
340 1.1 christos asection *sec,
341 1.1 christos bfd_byte *contents)
342 1.1 christos {
343 1.1 christos struct sframe_dec_info *sfd_info;
344 1.1 christos struct sframe_enc_info *sfe_info;
345 1.1 christos sframe_decoder_ctx *sfd_ctx;
346 1.1 christos sframe_encoder_ctx *sfe_ctx;
347 1.1 christos uint8_t sfd_ctx_abi_arch;
348 1.1 christos int8_t sfd_ctx_fixed_fp_offset;
349 1.1 christos int8_t sfd_ctx_fixed_ra_offset;
350 1.1 christos uint8_t dctx_version;
351 1.1 christos uint8_t ectx_version;
352 1.1.1.2 christos uint8_t dctx_flags;
353 1.1.1.2 christos uint8_t ectx_flags;
354 1.1 christos int encerr = 0;
355 1.1 christos
356 1.1 christos struct elf_link_hash_table *htab;
357 1.1 christos asection *cfsec;
358 1.1 christos
359 1.1 christos /* Sanity check - handle SFrame sections only. */
360 1.1 christos if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME)
361 1.1 christos return false;
362 1.1 christos
363 1.1 christos sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
364 1.1 christos sfd_ctx = sfd_info->sfd_ctx;
365 1.1 christos
366 1.1 christos htab = elf_hash_table (info);
367 1.1 christos sfe_info = &(htab->sfe_info);
368 1.1 christos sfe_ctx = sfe_info->sfe_ctx;
369 1.1 christos
370 1.1 christos /* All input bfds are expected to have a valid SFrame section. Even if
371 1.1 christos the SFrame section is empty with only a header, there must be a valid
372 1.1 christos SFrame decoder context by now. The SFrame encoder context, however,
373 1.1 christos will get set later here, if this is the first call to the function. */
374 1.1 christos if (sfd_ctx == NULL || sfe_info == NULL)
375 1.1 christos return false;
376 1.1 christos
377 1.1.1.2 christos dctx_flags = sframe_decoder_get_flags (sfd_ctx);
378 1.1.1.2 christos
379 1.1 christos if (htab->sfe_info.sfe_ctx == NULL)
380 1.1 christos {
381 1.1 christos sfd_ctx_abi_arch = sframe_decoder_get_abi_arch (sfd_ctx);
382 1.1 christos sfd_ctx_fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (sfd_ctx);
383 1.1 christos sfd_ctx_fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (sfd_ctx);
384 1.1 christos
385 1.1 christos /* Valid values are non-zero. */
386 1.1 christos if (!sfd_ctx_abi_arch)
387 1.1 christos return false;
388 1.1 christos
389 1.1.1.2 christos /* In-memory FDEs in the encoder object are unsorted during linking and
390 1.1.1.2 christos will be sorted before emission. Reset SFRAME_F_FDE_SORTED to aptly
391 1.1.1.2 christos reflect that (doing so has no other functional value at this time
392 1.1.1.2 christos though). */
393 1.1.1.2 christos uint8_t tflags = dctx_flags & ~SFRAME_F_FDE_SORTED;
394 1.1.1.2 christos /* ld always generates an output section with
395 1.1.1.2 christos SFRAME_F_FDE_FUNC_START_PCREL flag set. Later using
396 1.1.1.2 christos SFRAME_V2_GNU_AS_LD_ENCODING_FLAGS, it is enforced that the provided
397 1.1.1.2 christos input sections also have this flag set. */
398 1.1.1.2 christos tflags |= SFRAME_F_FDE_FUNC_START_PCREL;
399 1.1 christos htab->sfe_info.sfe_ctx = sframe_encode (SFRAME_VERSION_2,
400 1.1.1.2 christos tflags, /* SFrame flags. */
401 1.1 christos sfd_ctx_abi_arch,
402 1.1 christos sfd_ctx_fixed_fp_offset,
403 1.1 christos sfd_ctx_fixed_ra_offset,
404 1.1 christos &encerr);
405 1.1 christos /* Handle errors from sframe_encode. */
406 1.1 christos if (htab->sfe_info.sfe_ctx == NULL)
407 1.1 christos return false;
408 1.1 christos }
409 1.1 christos sfe_ctx = sfe_info->sfe_ctx;
410 1.1 christos
411 1.1 christos if (sfe_info->sframe_section == NULL)
412 1.1 christos {
413 1.1 christos /* Make sure things are set for an eventual write.
414 1.1 christos Size of the output section is not known until
415 1.1 christos _bfd_elf_write_section_sframe is ready with the buffer
416 1.1 christos to write out. */
417 1.1 christos cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe");
418 1.1 christos if (cfsec)
419 1.1 christos {
420 1.1 christos sfe_info->sframe_section = cfsec;
421 1.1 christos // elf_sframe (abfd) = cfsec;
422 1.1 christos }
423 1.1 christos else
424 1.1 christos return false;
425 1.1 christos }
426 1.1 christos
427 1.1 christos /* Check that all .sframe sections being linked have the same
428 1.1 christos ABI/arch. */
429 1.1 christos if (sframe_decoder_get_abi_arch (sfd_ctx)
430 1.1 christos != sframe_encoder_get_abi_arch (sfe_ctx))
431 1.1 christos {
432 1.1 christos _bfd_error_handler
433 1.1 christos (_("input SFrame sections with different abi prevent .sframe"
434 1.1 christos " generation"));
435 1.1 christos return false;
436 1.1 christos }
437 1.1 christos
438 1.1 christos /* Check that all .sframe sections being linked have the same version. */
439 1.1 christos dctx_version = sframe_decoder_get_version (sfd_ctx);
440 1.1 christos ectx_version = sframe_encoder_get_version (sfe_ctx);
441 1.1 christos if (dctx_version != SFRAME_VERSION_2 || dctx_version != ectx_version)
442 1.1 christos {
443 1.1 christos _bfd_error_handler
444 1.1 christos (_("input SFrame sections with different format versions prevent"
445 1.1 christos " .sframe generation"));
446 1.1 christos return false;
447 1.1 christos }
448 1.1 christos
449 1.1.1.2 christos /* Check that all SFrame sections being linked have the 'data encoding'
450 1.1.1.2 christos related flags set. The implementation does not support updating these
451 1.1.1.2 christos data encodings on the fly; confirm by checking the ectx_flags. */
452 1.1.1.2 christos ectx_flags = sframe_encoder_get_flags (sfe_ctx);
453 1.1.1.2 christos if ((dctx_flags & ectx_flags & SFRAME_V2_GNU_AS_LD_ENCODING_FLAGS)
454 1.1.1.2 christos != SFRAME_V2_GNU_AS_LD_ENCODING_FLAGS)
455 1.1.1.2 christos {
456 1.1.1.2 christos _bfd_error_handler
457 1.1.1.2 christos (_("SFrame sections with unexpected data encoding prevent"
458 1.1.1.2 christos " .sframe generation"));
459 1.1.1.2 christos return false;
460 1.1.1.2 christos }
461 1.1 christos
462 1.1 christos /* Iterate over the function descriptor entries and the FREs of the
463 1.1 christos function from the decoder context. Add each of them to the encoder
464 1.1 christos context, if suitable. */
465 1.1 christos uint32_t i = 0, j = 0, cur_fidx = 0;
466 1.1 christos
467 1.1 christos uint32_t num_fidx = sframe_decoder_get_num_fidx (sfd_ctx);
468 1.1 christos uint32_t num_enc_fidx = sframe_encoder_get_num_fidx (sfe_ctx);
469 1.1 christos
470 1.1 christos for (i = 0; i < num_fidx; i++)
471 1.1 christos {
472 1.1 christos unsigned int num_fres = 0;
473 1.1 christos int32_t func_start_addr;
474 1.1 christos bfd_vma address;
475 1.1 christos uint32_t func_size = 0;
476 1.1 christos unsigned char func_info = 0;
477 1.1 christos unsigned int r_offset = 0;
478 1.1 christos bool pltn_reloc_by_hand = false;
479 1.1 christos unsigned int pltn_r_offset = 0;
480 1.1 christos uint8_t rep_block_size = 0;
481 1.1 christos
482 1.1 christos if (!sframe_decoder_get_funcdesc_v2 (sfd_ctx, i, &num_fres, &func_size,
483 1.1 christos &func_start_addr, &func_info,
484 1.1 christos &rep_block_size))
485 1.1 christos {
486 1.1 christos /* If function belongs to a deleted section, skip editing the
487 1.1 christos function descriptor entry. */
488 1.1 christos if (sframe_decoder_func_deleted_p(sfd_info, i))
489 1.1 christos continue;
490 1.1 christos
491 1.1 christos /* Don't edit function descriptor entries for relocatable link. */
492 1.1 christos if (!bfd_link_relocatable (info))
493 1.1 christos {
494 1.1 christos if (!(sec->flags & SEC_LINKER_CREATED))
495 1.1 christos {
496 1.1 christos /* Get relocated contents by reading the value of the
497 1.1 christos relocated function start address at the beginning of the
498 1.1 christos function descriptor entry. */
499 1.1 christos r_offset = sframe_decoder_get_func_r_offset (sfd_info, i);
500 1.1 christos }
501 1.1 christos else
502 1.1 christos {
503 1.1 christos /* Expected to land here when SFrame stack trace info is
504 1.1 christos created dynamically for the .plt* sections. These
505 1.1 christos sections are expected to have upto two SFrame FDE entries.
506 1.1 christos Although the code should work for > 2, leaving this
507 1.1 christos assert here for safety. */
508 1.1 christos BFD_ASSERT (num_fidx <= 2);
509 1.1 christos /* For the first entry, we know the offset of the SFrame FDE's
510 1.1 christos sfde_func_start_address. Side note: see how the value
511 1.1 christos of PLT_SFRAME_FDE_START_OFFSET is also set to the
512 1.1 christos same. */
513 1.1 christos r_offset = sframe_decoder_get_hdr_size (sfd_ctx);
514 1.1 christos /* For any further SFrame FDEs, the generator has already put
515 1.1 christos in an offset in place of sfde_func_start_address of the
516 1.1 christos corresponding FDE. We will use it by hand to relocate. */
517 1.1 christos if (i > 0)
518 1.1 christos {
519 1.1 christos pltn_r_offset
520 1.1 christos = r_offset + (i * sizeof (sframe_func_desc_entry));
521 1.1 christos pltn_reloc_by_hand = true;
522 1.1 christos }
523 1.1 christos }
524 1.1 christos
525 1.1 christos /* Get the SFrame FDE function start address after relocation. */
526 1.1 christos address = sframe_read_value (abfd, contents, r_offset, 4);
527 1.1 christos if (pltn_reloc_by_hand)
528 1.1 christos address += sframe_read_value (abfd, contents,
529 1.1 christos pltn_r_offset, 4);
530 1.1 christos address += (sec->output_offset + r_offset);
531 1.1.1.2 christos /* SFrame FDE function start address is an offset from the
532 1.1.1.2 christos sfde_func_start_address field to the start PC. The
533 1.1.1.2 christos calculation below is the distance of sfde_func_start_address
534 1.1.1.2 christos field from the start of the output SFrame section. */
535 1.1.1.2 christos uint32_t offsetof_fde_in_sec
536 1.1.1.2 christos = sframe_encoder_get_offsetof_fde_start_addr (sfe_ctx,
537 1.1.1.2 christos cur_fidx + num_enc_fidx,
538 1.1.1.2 christos NULL);
539 1.1.1.2 christos address -= offsetof_fde_in_sec;
540 1.1 christos
541 1.1 christos /* FIXME For testing only. Cleanup later. */
542 1.1 christos // address += (sec->output_section->vma);
543 1.1 christos
544 1.1 christos func_start_addr = address;
545 1.1 christos }
546 1.1 christos
547 1.1 christos /* Update the encoder context with updated content. */
548 1.1 christos int err = sframe_encoder_add_funcdesc_v2 (sfe_ctx, func_start_addr,
549 1.1 christos func_size, func_info,
550 1.1 christos rep_block_size, num_fres);
551 1.1 christos cur_fidx++;
552 1.1 christos BFD_ASSERT (!err);
553 1.1 christos }
554 1.1 christos
555 1.1 christos for (j = 0; j < num_fres; j++)
556 1.1 christos {
557 1.1 christos sframe_frame_row_entry fre;
558 1.1 christos if (!sframe_decoder_get_fre (sfd_ctx, i, j, &fre))
559 1.1 christos {
560 1.1 christos int err = sframe_encoder_add_fre (sfe_ctx,
561 1.1 christos cur_fidx-1+num_enc_fidx,
562 1.1 christos &fre);
563 1.1 christos BFD_ASSERT (!err);
564 1.1 christos }
565 1.1 christos }
566 1.1 christos }
567 1.1.1.2 christos sfd_info->sfd_state = SFRAME_SEC_MERGED;
568 1.1 christos /* Free the SFrame decoder context. */
569 1.1 christos sframe_decoder_free (&sfd_ctx);
570 1.1 christos
571 1.1 christos return true;
572 1.1 christos }
573 1.1 christos
574 1.1.1.2 christos /* Adjust an address in the .sframe section. Given OFFSET within
575 1.1.1.2 christos SEC, this returns the new offset in the merged .sframe section,
576 1.1.1.2 christos or -1 if the address refers to an FDE which has been removed.
577 1.1.1.2 christos
578 1.1.1.2 christos PS: This function assumes that _bfd_elf_merge_section_sframe has
579 1.1.1.2 christos not been called on the input section SEC yet. Note how it uses
580 1.1.1.2 christos sframe_encoder_get_num_fidx () to figure out the offset of FDE
581 1.1.1.2 christos in the output section. */
582 1.1.1.2 christos
583 1.1.1.2 christos bfd_vma
584 1.1.1.2 christos _bfd_elf_sframe_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED,
585 1.1.1.2 christos struct bfd_link_info *info,
586 1.1.1.2 christos asection *sec,
587 1.1.1.2 christos bfd_vma offset)
588 1.1.1.2 christos {
589 1.1.1.2 christos struct sframe_dec_info *sfd_info;
590 1.1.1.2 christos struct sframe_enc_info *sfe_info;
591 1.1.1.2 christos sframe_decoder_ctx *sfd_ctx;
592 1.1.1.2 christos sframe_encoder_ctx *sfe_ctx;
593 1.1.1.2 christos struct elf_link_hash_table *htab;
594 1.1.1.2 christos
595 1.1.1.2 christos unsigned int sec_fde_idx, out_num_fdes;
596 1.1.1.2 christos unsigned int sfd_num_fdes, sfe_num_fdes;
597 1.1.1.2 christos uint32_t sfd_fde_offset;
598 1.1.1.2 christos bfd_vma new_offset;
599 1.1.1.2 christos
600 1.1.1.2 christos if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME)
601 1.1.1.2 christos return offset;
602 1.1.1.2 christos
603 1.1.1.2 christos sfd_info = elf_section_data (sec)->sec_info;
604 1.1.1.2 christos sfd_ctx = sfd_info->sfd_ctx;
605 1.1.1.2 christos sfd_num_fdes = sframe_decoder_get_num_fidx (sfd_ctx);
606 1.1.1.2 christos
607 1.1.1.2 christos BFD_ASSERT (sfd_info->sfd_state == SFRAME_SEC_DECODED);
608 1.1.1.2 christos
609 1.1.1.2 christos htab = elf_hash_table (info);
610 1.1.1.2 christos sfe_info = &(htab->sfe_info);
611 1.1.1.2 christos sfe_ctx = sfe_info->sfe_ctx;
612 1.1.1.2 christos sfe_num_fdes = sframe_encoder_get_num_fidx (sfe_ctx);
613 1.1.1.2 christos
614 1.1.1.2 christos /* The index of this FDE in the output section depends on number of deleted
615 1.1.1.2 christos functions (between index 0 and sec_fde_idx), if any. */
616 1.1.1.2 christos out_num_fdes = 0;
617 1.1.1.2 christos sec_fde_idx = 0;
618 1.1.1.2 christos for (unsigned int i = 0; i < sfd_num_fdes; i++)
619 1.1.1.2 christos {
620 1.1.1.2 christos sfd_fde_offset = sframe_decoder_get_offsetof_fde_start_addr (sfd_ctx,
621 1.1.1.2 christos i, NULL);
622 1.1.1.2 christos if (!sframe_decoder_func_deleted_p (sfd_info, i))
623 1.1.1.2 christos out_num_fdes++;
624 1.1.1.2 christos
625 1.1.1.2 christos if (sfd_fde_offset == offset)
626 1.1.1.2 christos {
627 1.1.1.2 christos /* Found the index of the FDE (at OFFSET) in the input section. */
628 1.1.1.2 christos sec_fde_idx = i;
629 1.1.1.2 christos break;
630 1.1.1.2 christos }
631 1.1.1.2 christos }
632 1.1.1.2 christos
633 1.1.1.2 christos if (sframe_decoder_func_deleted_p (sfd_info, sec_fde_idx))
634 1.1.1.2 christos return (bfd_vma) -1;
635 1.1.1.2 christos
636 1.1.1.2 christos /* The number of FDEs in the output SFrame section. Note that the output
637 1.1.1.2 christos index of the FDE of interest will be (out_num_fdes - 1). */
638 1.1.1.2 christos out_num_fdes += sfe_num_fdes;
639 1.1.1.2 christos
640 1.1.1.2 christos new_offset = sframe_decoder_get_offsetof_fde_start_addr (sfd_ctx,
641 1.1.1.2 christos out_num_fdes - 1,
642 1.1.1.2 christos NULL);
643 1.1.1.2 christos /* Recall that SFrame section merging has distinct requirements: All SFrame
644 1.1.1.2 christos FDEs from input sections are clubbed together in the beginning of the
645 1.1.1.2 christos output section. So, at this point in the current function, the new_offset
646 1.1.1.2 christos is the correct offset in the merged output SFrame section. Note, however,
647 1.1.1.2 christos that the default mechanism in the _elf_link_input_bfd will do the
648 1.1.1.2 christos following adjustment:
649 1.1.1.2 christos irela->r_offset += o->output_offset;
650 1.1.1.2 christos for all section types. However, such an adjustment in the RELA offset is
651 1.1.1.2 christos _not_ needed for SFrame sections. Perform the reverse adjustment here so
652 1.1.1.2 christos that the default mechanism does not need additional SFrame specific
653 1.1.1.2 christos checks. */
654 1.1.1.2 christos new_offset -= sec->output_offset;
655 1.1.1.2 christos
656 1.1.1.2 christos return new_offset;
657 1.1.1.2 christos }
658 1.1.1.2 christos
659 1.1 christos /* Write out the .sframe section. This must be called after
660 1.1 christos _bfd_elf_merge_section_sframe has been called on all input
661 1.1 christos .sframe sections. */
662 1.1 christos
663 1.1 christos bool
664 1.1 christos _bfd_elf_write_section_sframe (bfd *abfd, struct bfd_link_info *info)
665 1.1 christos {
666 1.1 christos bool retval = true;
667 1.1 christos
668 1.1 christos struct elf_link_hash_table *htab;
669 1.1 christos struct sframe_enc_info *sfe_info;
670 1.1 christos sframe_encoder_ctx *sfe_ctx;
671 1.1 christos asection *sec;
672 1.1 christos void *contents;
673 1.1 christos size_t sec_size;
674 1.1 christos int err = 0;
675 1.1 christos
676 1.1 christos htab = elf_hash_table (info);
677 1.1 christos sfe_info = &htab->sfe_info;
678 1.1 christos sec = sfe_info->sframe_section;
679 1.1 christos sfe_ctx = sfe_info->sfe_ctx;
680 1.1 christos
681 1.1 christos if (sec == NULL)
682 1.1 christos return true;
683 1.1 christos
684 1.1 christos contents = sframe_encoder_write (sfe_ctx, &sec_size, &err);
685 1.1 christos sec->size = (bfd_size_type) sec_size;
686 1.1 christos
687 1.1 christos if (!bfd_set_section_contents (abfd, sec->output_section, contents,
688 1.1 christos (file_ptr) sec->output_offset,
689 1.1 christos sec->size))
690 1.1 christos retval = false;
691 1.1.1.2 christos else
692 1.1 christos {
693 1.1 christos Elf_Internal_Shdr *hdr = &elf_section_data (sec)->this_hdr;
694 1.1 christos hdr->sh_size = sec->size;
695 1.1 christos }
696 1.1 christos
697 1.1 christos sframe_encoder_free (&sfe_ctx);
698 1.1 christos
699 1.1 christos return retval;
700 1.1 christos }
701