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