]>
Commit | Line | Data |
---|---|---|
cf0e0a0b | 1 | /* .sframe section processing. |
d87bef3a | 2 | Copyright (C) 2022-2023 Free Software Foundation, Inc. |
cf0e0a0b IB |
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 | ||
27 | /* Return TRUE if the function has been marked for deletion during the linking | |
28 | process. */ | |
29 | ||
30 | static bool | |
31 | sframe_decoder_func_deleted_p (struct sframe_dec_info *sfd_info, | |
32 | unsigned int func_idx) | |
33 | { | |
34 | if (func_idx < sfd_info->sfd_fde_count) | |
35 | return sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p; | |
36 | ||
37 | return false; | |
38 | } | |
39 | ||
40 | /* Mark the function in the decoder info for deletion. */ | |
41 | ||
42 | static void | |
43 | sframe_decoder_mark_func_deleted (struct sframe_dec_info *sfd_info, | |
44 | unsigned int func_idx) | |
45 | { | |
46 | if (func_idx < sfd_info->sfd_fde_count) | |
47 | sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p = true; | |
48 | } | |
49 | ||
50 | /* Get the relocation offset from the decoder info for the given function. */ | |
51 | ||
52 | static unsigned int | |
53 | sframe_decoder_get_func_r_offset (struct sframe_dec_info *sfd_info, | |
54 | unsigned int func_idx) | |
55 | { | |
56 | BFD_ASSERT (func_idx < sfd_info->sfd_fde_count); | |
57 | unsigned int func_r_offset | |
58 | = sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset; | |
59 | /* There must have been a reloc. */ | |
60 | BFD_ASSERT (func_r_offset); | |
61 | return func_r_offset; | |
62 | } | |
63 | ||
64 | /* Bookkeep the function relocation offset in the decoder info. */ | |
65 | ||
66 | static void | |
67 | sframe_decoder_set_func_r_offset (struct sframe_dec_info *sfd_info, | |
68 | unsigned int func_idx, | |
69 | unsigned int r_offset) | |
70 | { | |
71 | if (func_idx < sfd_info->sfd_fde_count) | |
72 | sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset = r_offset; | |
73 | } | |
74 | ||
75 | /* Get the relocation index in the elf_reloc_cookie for the function. */ | |
76 | ||
77 | static unsigned int | |
78 | sframe_decoder_get_func_reloc_index (struct sframe_dec_info *sfd_info, | |
79 | unsigned int func_idx) | |
80 | { | |
81 | BFD_ASSERT (func_idx < sfd_info->sfd_fde_count); | |
82 | return sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index; | |
83 | } | |
84 | ||
85 | /* Bookkeep the relocation index in the elf_reloc_cookie for the function. */ | |
86 | ||
87 | static void | |
88 | sframe_decoder_set_func_reloc_index (struct sframe_dec_info *sfd_info, | |
89 | unsigned int func_idx, | |
90 | unsigned int reloc_index) | |
91 | { | |
92 | if (func_idx < sfd_info->sfd_fde_count) | |
93 | sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index = reloc_index; | |
94 | } | |
95 | ||
96 | /* Initialize the set of additional information in CFD_INFO, | |
97 | needed for linking SEC. Returns TRUE if setup is done successfully. */ | |
98 | ||
99 | static bool | |
100 | sframe_decoder_init_func_bfdinfo (asection *sec, | |
101 | struct sframe_dec_info *sfd_info, | |
102 | struct elf_reloc_cookie *cookie) | |
103 | { | |
104 | unsigned int fde_count; | |
105 | unsigned int func_bfdinfo_size, i; | |
106 | ||
107 | fde_count = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx); | |
108 | sfd_info->sfd_fde_count = fde_count; | |
109 | ||
110 | /* Allocate and clear the memory. */ | |
111 | func_bfdinfo_size = (sizeof (struct sframe_func_bfdinfo)) * fde_count; | |
112 | sfd_info->sfd_func_bfdinfo | |
113 | = (struct sframe_func_bfdinfo*) bfd_malloc (func_bfdinfo_size); | |
114 | if (sfd_info->sfd_func_bfdinfo == NULL) | |
115 | return false; | |
116 | memset (sfd_info->sfd_func_bfdinfo, 0, func_bfdinfo_size); | |
117 | ||
118 | /* For linker generated .sframe sections, we have no relocs. Skip. */ | |
119 | if ((sec->flags & SEC_LINKER_CREATED) && cookie->rels == NULL) | |
120 | return true; | |
121 | ||
122 | for (i = 0; i < fde_count; i++) | |
123 | { | |
124 | cookie->rel = cookie->rels + i; | |
125 | BFD_ASSERT (cookie->rel < cookie->relend); | |
126 | /* Bookkeep the relocation offset and relocation index of each function | |
127 | for later use. */ | |
128 | sframe_decoder_set_func_r_offset (sfd_info, i, cookie->rel->r_offset); | |
129 | sframe_decoder_set_func_reloc_index (sfd_info, i, | |
130 | (cookie->rel - cookie->rels)); | |
131 | ||
132 | cookie->rel++; | |
133 | } | |
134 | BFD_ASSERT (cookie->rel == cookie->relend); | |
135 | ||
136 | return true; | |
137 | } | |
138 | ||
139 | /* Read the value from CONTENTS at the specified OFFSET for the given ABFD. */ | |
140 | ||
141 | static bfd_vma | |
142 | sframe_read_value (bfd *abfd, bfd_byte *contents, unsigned int offset, | |
143 | unsigned int width) | |
144 | { | |
145 | BFD_ASSERT (contents && offset); | |
146 | /* Supporting the usecase of reading only the 4-byte relocated | |
147 | value (signed offset for func start addr) for now. */ | |
148 | BFD_ASSERT (width == 4); | |
149 | /* FIXME endianness ?? */ | |
150 | unsigned char *buf = contents + offset; | |
151 | bfd_vma value = bfd_get_signed_32 (abfd, buf); | |
152 | return value; | |
153 | } | |
154 | ||
155 | /* Return true if there is at least one non-empty .sframe section in | |
156 | input files. Can only be called after ld has mapped input to | |
157 | output sections, and before sections are stripped. */ | |
158 | ||
159 | bool | |
160 | _bfd_elf_sframe_present (struct bfd_link_info *info) | |
161 | { | |
162 | asection *sframe = bfd_get_section_by_name (info->output_bfd, ".sframe"); | |
163 | ||
164 | if (sframe == NULL) | |
165 | return false; | |
166 | ||
167 | /* Count only sections which have at least a single FDE. */ | |
168 | for (sframe = sframe->map_head.s; sframe != NULL; sframe = sframe->map_head.s) | |
169 | /* Note that this may become an approximate check in the future when | |
170 | some ABI/arch begin to use the sfh_auxhdr_len. When sfh_auxhdr_len has | |
171 | non-zero value, it will need to be accounted for in the calculation of | |
172 | the SFrame header size. */ | |
173 | if (sframe->size > sizeof (sframe_header)) | |
174 | return true; | |
175 | return false; | |
176 | } | |
177 | ||
178 | /* Try to parse .sframe section SEC, which belongs to ABFD. Store the | |
179 | information in the section's sec_info field on success. COOKIE | |
180 | describes the relocations in SEC. | |
181 | ||
182 | Returns TRUE if success, FALSE if any error or failure. */ | |
183 | ||
184 | bool | |
185 | _bfd_elf_parse_sframe (bfd *abfd, | |
186 | struct bfd_link_info *info ATTRIBUTE_UNUSED, | |
187 | asection *sec, struct elf_reloc_cookie *cookie) | |
188 | { | |
189 | bfd_byte *sfbuf = NULL; | |
190 | struct sframe_dec_info *sfd_info; | |
191 | sframe_decoder_ctx *sfd_ctx; | |
192 | bfd_size_type sf_size; | |
193 | int decerr = 0; | |
194 | ||
195 | if (sec->size == 0 | |
81ff113f | 196 | || (sec->flags & SEC_HAS_CONTENTS) == 0 |
cf0e0a0b IB |
197 | || sec->sec_info_type != SEC_INFO_TYPE_NONE) |
198 | { | |
199 | /* This file does not contain .sframe information. */ | |
200 | return false; | |
201 | } | |
202 | ||
203 | if (bfd_is_abs_section (sec->output_section)) | |
204 | { | |
205 | /* At least one of the sections is being discarded from the | |
206 | link, so we should just ignore them. */ | |
207 | return false; | |
208 | } | |
209 | ||
53d8d3f0 | 210 | /* Read the SFrame stack trace information from abfd. */ |
cf0e0a0b IB |
211 | if (!bfd_malloc_and_get_section (abfd, sec, &sfbuf)) |
212 | goto fail_no_free; | |
213 | ||
214 | /* Decode the buffer and keep decoded contents for later use. | |
215 | Relocations are performed later, but are such that the section's | |
216 | size is unaffected. */ | |
217 | sfd_info = bfd_malloc (sizeof (struct sframe_dec_info)); | |
218 | sf_size = sec->size; | |
219 | ||
220 | sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr); | |
221 | sfd_ctx = sfd_info->sfd_ctx; | |
222 | if (!sfd_ctx) | |
223 | /* Free'ing up any memory held by decoder context is done by | |
224 | sframe_decode in case of error. */ | |
225 | goto fail_no_free; | |
226 | ||
227 | if (!sframe_decoder_init_func_bfdinfo (sec, sfd_info, cookie)) | |
228 | { | |
229 | sframe_decoder_free (&sfd_ctx); | |
230 | goto fail_no_free; | |
231 | } | |
232 | ||
233 | elf_section_data (sec)->sec_info = sfd_info; | |
234 | sec->sec_info_type = SEC_INFO_TYPE_SFRAME; | |
235 | ||
236 | goto success; | |
237 | ||
238 | fail_no_free: | |
239 | _bfd_error_handler | |
240 | (_("error in %pB(%pA); no .sframe will be created"), | |
241 | abfd, sec); | |
242 | return false; | |
243 | success: | |
244 | free (sfbuf); | |
245 | return true; | |
246 | } | |
247 | ||
248 | /* This function is called for each input file before the .sframe section | |
249 | is relocated. It marks the SFrame FDE for the discarded functions for | |
250 | deletion. | |
251 | ||
252 | The function returns TRUE iff any entries have been deleted. */ | |
253 | ||
254 | bool | |
255 | _bfd_elf_discard_section_sframe | |
256 | (asection *sec, | |
257 | bool (*reloc_symbol_deleted_p) (bfd_vma, void *), | |
258 | struct elf_reloc_cookie *cookie) | |
259 | { | |
260 | bool changed; | |
261 | bool keep; | |
262 | unsigned int i; | |
263 | unsigned int func_desc_offset; | |
264 | unsigned int num_fidx; | |
265 | struct sframe_dec_info *sfd_info; | |
266 | ||
267 | changed = false; | |
268 | /* FIXME - if relocatable link and changed = true, how does the final | |
269 | .rela.sframe get updated ?. */ | |
270 | keep = false; | |
271 | ||
272 | sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info; | |
273 | ||
274 | /* Skip checking for the linker created .sframe sections | |
275 | (for PLT sections). */ | |
276 | if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL) | |
277 | { | |
278 | num_fidx = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx); | |
279 | for (i = 0; i < num_fidx; i++) | |
280 | { | |
281 | func_desc_offset = sframe_decoder_get_func_r_offset (sfd_info, i); | |
282 | ||
283 | cookie->rel = cookie->rels | |
284 | + sframe_decoder_get_func_reloc_index (sfd_info, i); | |
285 | keep = !(*reloc_symbol_deleted_p) (func_desc_offset, cookie); | |
286 | ||
287 | if (!keep) | |
288 | { | |
289 | sframe_decoder_mark_func_deleted (sfd_info, i); | |
290 | changed = true; | |
291 | } | |
292 | } | |
293 | } | |
294 | return changed; | |
295 | } | |
296 | ||
297 | /* Update the reference to the output .sframe section in the output ELF | |
298 | BFD ABFD. Returns true if no error. */ | |
299 | ||
300 | bool | |
301 | _bfd_elf_set_section_sframe (bfd *abfd, | |
302 | struct bfd_link_info *info) | |
303 | { | |
304 | asection *cfsec; | |
305 | ||
306 | cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe"); | |
307 | if (!cfsec) | |
308 | return false; | |
309 | ||
310 | elf_sframe (abfd) = cfsec; | |
311 | ||
312 | return true; | |
313 | } | |
314 | ||
315 | /* Merge .sframe section SEC. This is called with the relocated | |
316 | CONTENTS. */ | |
317 | ||
318 | bool | |
319 | _bfd_elf_merge_section_sframe (bfd *abfd, | |
320 | struct bfd_link_info *info, | |
321 | asection *sec, | |
322 | bfd_byte *contents) | |
323 | { | |
324 | struct sframe_dec_info *sfd_info; | |
325 | struct sframe_enc_info *sfe_info; | |
326 | sframe_decoder_ctx *sfd_ctx; | |
327 | sframe_encoder_ctx *sfe_ctx; | |
328 | unsigned char sfd_ctx_abi_arch; | |
329 | int8_t sfd_ctx_fixed_fp_offset; | |
330 | int8_t sfd_ctx_fixed_ra_offset; | |
331 | int encerr = 0; | |
332 | ||
333 | struct elf_link_hash_table *htab; | |
334 | asection *cfsec; | |
335 | ||
336 | /* Sanity check - handle SFrame sections only. */ | |
337 | if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME) | |
338 | return false; | |
339 | ||
340 | sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info; | |
341 | sfd_ctx = sfd_info->sfd_ctx; | |
342 | ||
343 | htab = elf_hash_table (info); | |
344 | sfe_info = &(htab->sfe_info); | |
345 | sfe_ctx = sfe_info->sfe_ctx; | |
346 | ||
347 | /* All input bfds are expected to have a valid SFrame section. Even if | |
348 | the SFrame section is empty with only a header, there must be a valid | |
349 | SFrame decoder context by now. The SFrame encoder context, however, | |
350 | will get set later here, if this is the first call to the function. */ | |
351 | if (sfd_ctx == NULL || sfe_info == NULL) | |
352 | return false; | |
353 | ||
354 | if (htab->sfe_info.sfe_ctx == NULL) | |
355 | { | |
356 | sfd_ctx_abi_arch = sframe_decoder_get_abi_arch (sfd_ctx); | |
357 | sfd_ctx_fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (sfd_ctx); | |
358 | sfd_ctx_fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (sfd_ctx); | |
359 | ||
360 | /* Valid values are non-zero. */ | |
361 | if (!sfd_ctx_abi_arch) | |
362 | return false; | |
363 | ||
364 | htab->sfe_info.sfe_ctx = sframe_encode (SFRAME_VERSION_1, | |
365 | 0, /* SFrame flags. */ | |
366 | sfd_ctx_abi_arch, | |
367 | sfd_ctx_fixed_fp_offset, | |
368 | sfd_ctx_fixed_ra_offset, | |
369 | &encerr); | |
370 | /* Handle errors from sframe_encode. */ | |
371 | if (htab->sfe_info.sfe_ctx == NULL) | |
372 | return false; | |
373 | } | |
374 | sfe_ctx = sfe_info->sfe_ctx; | |
375 | ||
376 | if (sfe_info->sframe_section == NULL) | |
377 | { | |
378 | /* Make sure things are set for an eventual write. | |
379 | Size of the output section is not known until | |
380 | _bfd_elf_write_section_sframe is ready with the buffer | |
381 | to write out. */ | |
382 | cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe"); | |
383 | if (cfsec) | |
384 | { | |
385 | sfe_info->sframe_section = cfsec; | |
386 | // elf_sframe (abfd) = cfsec; | |
387 | } | |
388 | else | |
389 | return false; | |
390 | } | |
391 | ||
392 | /* Check that all .sframe sections being linked have the same | |
393 | ABI/arch. */ | |
394 | if (sframe_decoder_get_abi_arch (sfd_ctx) | |
395 | != sframe_encoder_get_abi_arch (sfe_ctx)) | |
396 | { | |
397 | _bfd_error_handler | |
398 | (_("input SFrame sections with different abi prevent .sframe" | |
399 | " generation")); | |
400 | return false; | |
401 | } | |
402 | ||
403 | /* Iterate over the function descriptor entries and the FREs of the | |
404 | function from the decoder context. Add each of them to the encoder | |
405 | context, if suitable. */ | |
406 | unsigned int i = 0, j = 0, cur_fidx = 0; | |
407 | ||
408 | unsigned int num_fidx = sframe_decoder_get_num_fidx (sfd_ctx); | |
409 | unsigned int num_enc_fidx = sframe_encoder_get_num_fidx (sfe_ctx); | |
410 | ||
411 | for (i = 0; i < num_fidx; i++) | |
412 | { | |
413 | unsigned int num_fres = 0; | |
414 | int32_t func_start_address; | |
415 | bfd_vma address; | |
416 | uint32_t func_size = 0; | |
417 | unsigned char func_info = 0; | |
418 | unsigned int r_offset = 0; | |
419 | bool pltn_reloc_by_hand = false; | |
420 | unsigned int pltn_r_offset = 0; | |
421 | ||
422 | if (!sframe_decoder_get_funcdesc (sfd_ctx, i, &num_fres, &func_size, | |
423 | &func_start_address, &func_info)) | |
424 | { | |
425 | /* If function belongs to a deleted section, skip editing the | |
426 | function descriptor entry. */ | |
427 | if (sframe_decoder_func_deleted_p(sfd_info, i)) | |
428 | continue; | |
429 | ||
430 | /* Don't edit function descriptor entries for relocatable link. */ | |
431 | if (!bfd_link_relocatable (info)) | |
432 | { | |
433 | if (!(sec->flags & SEC_LINKER_CREATED)) | |
434 | { | |
435 | /* Get relocated contents by reading the value of the | |
436 | relocated function start address at the beginning of the | |
437 | function descriptor entry. */ | |
438 | r_offset = sframe_decoder_get_func_r_offset (sfd_info, i); | |
439 | } | |
440 | else | |
441 | { | |
53d8d3f0 IB |
442 | /* Expected to land here when SFrame stack trace info is |
443 | created dynamically for the .plt* sections. These | |
444 | sections are expected to have upto two SFrame FDE entries. | |
445 | Although the code should work for > 2, leaving this | |
446 | assert here for safety. */ | |
cf0e0a0b IB |
447 | BFD_ASSERT (num_fidx <= 2); |
448 | /* For the first entry, we know the offset of the SFrame FDE's | |
449 | sfde_func_start_address. Side note: see how the value | |
450 | of PLT_SFRAME_FDE_START_OFFSET is also set to the | |
451 | same. */ | |
452 | r_offset = sframe_decoder_get_hdr_size (sfd_ctx); | |
453 | /* For any further SFrame FDEs, the generator has already put | |
454 | in an offset in place of sfde_func_start_address of the | |
455 | corresponding FDE. We will use it by hand to relocate. */ | |
456 | if (i > 0) | |
457 | { | |
458 | pltn_r_offset | |
459 | = r_offset + (i * sizeof (sframe_func_desc_entry)); | |
460 | pltn_reloc_by_hand = true; | |
461 | } | |
462 | } | |
463 | ||
464 | /* Get the SFrame FDE function start address after relocation. */ | |
465 | address = sframe_read_value (abfd, contents, r_offset, 4); | |
466 | if (pltn_reloc_by_hand) | |
467 | address += sframe_read_value (abfd, contents, | |
468 | pltn_r_offset, 4); | |
469 | address += (sec->output_offset + r_offset); | |
470 | ||
471 | /* FIXME For testing only. Cleanup later. */ | |
472 | // address += (sec->output_section->vma); | |
473 | ||
474 | func_start_address = address; | |
475 | } | |
476 | ||
477 | /* Update the encoder context with updated content. */ | |
478 | int err = sframe_encoder_add_funcdesc (sfe_ctx, func_start_address, | |
479 | func_size, func_info, | |
480 | num_fres); | |
481 | cur_fidx++; | |
482 | BFD_ASSERT (!err); | |
483 | } | |
484 | ||
485 | for (j = 0; j < num_fres; j++) | |
486 | { | |
487 | sframe_frame_row_entry fre; | |
488 | if (!sframe_decoder_get_fre (sfd_ctx, i, j, &fre)) | |
489 | { | |
490 | int err = sframe_encoder_add_fre (sfe_ctx, | |
491 | cur_fidx-1+num_enc_fidx, | |
492 | &fre); | |
493 | BFD_ASSERT (!err); | |
494 | } | |
495 | } | |
496 | } | |
497 | /* Free the SFrame decoder context. */ | |
498 | sframe_decoder_free (&sfd_ctx); | |
499 | ||
500 | return true; | |
501 | } | |
502 | ||
503 | /* Write out the .sframe section. This must be called after | |
504 | _bfd_elf_merge_section_sframe has been called on all input | |
505 | .sframe sections. */ | |
506 | ||
507 | bool | |
508 | _bfd_elf_write_section_sframe (bfd *abfd, struct bfd_link_info *info) | |
509 | { | |
510 | bool retval = true; | |
511 | ||
512 | struct elf_link_hash_table *htab; | |
513 | struct sframe_enc_info *sfe_info; | |
514 | sframe_encoder_ctx *sfe_ctx; | |
515 | asection *sec; | |
516 | void *contents; | |
517 | size_t sec_size; | |
518 | int err = 0; | |
519 | ||
520 | htab = elf_hash_table (info); | |
521 | sfe_info = &htab->sfe_info; | |
522 | sec = sfe_info->sframe_section; | |
523 | sfe_ctx = sfe_info->sfe_ctx; | |
524 | ||
525 | if (sec == NULL) | |
526 | return true; | |
527 | ||
528 | contents = sframe_encoder_write (sfe_ctx, &sec_size, &err); | |
529 | sec->size = (bfd_size_type) sec_size; | |
530 | ||
531 | if (!bfd_set_section_contents (abfd, sec->output_section, contents, | |
532 | (file_ptr) sec->output_offset, | |
533 | sec->size)) | |
534 | retval = false; | |
535 | else if (!bfd_link_relocatable (info)) | |
536 | { | |
537 | Elf_Internal_Shdr *hdr = &elf_section_data (sec)->this_hdr; | |
538 | hdr->sh_size = sec->size; | |
539 | } | |
540 | /* For relocatable links, do not update the section size as the section | |
541 | contents have not been relocated. */ | |
542 | ||
543 | sframe_encoder_free (&sfe_ctx); | |
544 | ||
545 | return retval; | |
546 | } |