]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame_incremental - libsframe/sframe.c
Correctly handle L'\\'
[thirdparty/binutils-gdb.git] / libsframe / sframe.c
... / ...
CommitLineData
1/* sframe.c - SFrame decoder/encoder.
2
3 Copyright (C) 2022-2025 Free Software Foundation, Inc.
4
5 This file is part of libsframe.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include "config.h"
21#include <stdio.h>
22#include <stdlib.h>
23#include <stdarg.h>
24#include <string.h>
25#include <stddef.h>
26#include "sframe-impl.h"
27#include "swap.h"
28
29struct sf_fde_tbl
30{
31 unsigned int count;
32 unsigned int alloced;
33 sframe_func_desc_entry entry[1];
34};
35
36struct sf_fre_tbl
37{
38 unsigned int count;
39 unsigned int alloced;
40 sframe_frame_row_entry entry[1];
41};
42
43#define _sf_printflike_(string_index,first_to_check) \
44 __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
45
46static void debug_printf (const char *, ...);
47
48static int _sframe_debug; /* Control for printing out debug info. */
49static int number_of_entries = 64;
50
51static void
52sframe_init_debug (void)
53{
54 static int inited;
55
56 if (!inited)
57 {
58 _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
59 inited = 1;
60 }
61}
62
63_sf_printflike_ (1, 2)
64static void debug_printf (const char *format, ...)
65{
66 if (_sframe_debug)
67 {
68 va_list args;
69
70 va_start (args, format);
71 vfprintf (stderr, format, args);
72 va_end (args);
73 }
74}
75
76/* Generate bitmask of given size in bytes. This is used for
77 some checks on the FRE start address.
78 SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
79 SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
80 SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ]. */
81#define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
82 (((uint64_t)1 << (size_in_bytes*8)) - 1)
83
84/* Store the specified error code into errp if it is non-NULL.
85 Return SFRAME_ERR. */
86
87static int
88sframe_set_errno (int *errp, int error)
89{
90 if (errp != NULL)
91 *errp = error;
92 return SFRAME_ERR;
93}
94
95/* Store the specified error code into errp if it is non-NULL.
96 Return NULL. */
97
98static void *
99sframe_ret_set_errno (int *errp, int error)
100{
101 if (errp != NULL)
102 *errp = error;
103 return NULL;
104}
105
106/* Get the SFrame header size. */
107
108static uint32_t
109sframe_get_hdr_size (sframe_header *sfh)
110{
111 return SFRAME_V1_HDR_SIZE (*sfh);
112}
113
114/* Access functions for frame row entry data. */
115
116static uint8_t
117sframe_fre_get_offset_count (uint8_t fre_info)
118{
119 return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
120}
121
122static uint8_t
123sframe_fre_get_offset_size (uint8_t fre_info)
124{
125 return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
126}
127
128static bool
129sframe_get_fre_ra_mangled_p (uint8_t fre_info)
130{
131 return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
132}
133
134/* Access functions for info from function descriptor entry. */
135
136static uint32_t
137sframe_get_fre_type (sframe_func_desc_entry *fdep)
138{
139 uint32_t fre_type = 0;
140 if (fdep)
141 fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
142 return fre_type;
143}
144
145static uint32_t
146sframe_get_fde_type (sframe_func_desc_entry *fdep)
147{
148 uint32_t fde_type = 0;
149 if (fdep)
150 fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
151 return fde_type;
152}
153
154/* Check if flipping is needed, based on ENDIAN. */
155
156static int
157need_swapping (int endian)
158{
159 unsigned int ui = 1;
160 char *c = (char *)&ui;
161 int is_little = (int)*c;
162
163 switch (endian)
164 {
165 case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
166 case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
167 return !is_little;
168 case SFRAME_ABI_AARCH64_ENDIAN_BIG:
169 return is_little;
170 default:
171 break;
172 }
173
174 return 0;
175}
176
177/* Flip the endianness of the SFrame header. */
178
179static void
180flip_header (sframe_header *sfheader)
181{
182 swap_thing (sfheader->sfh_preamble.sfp_magic);
183 swap_thing (sfheader->sfh_preamble.sfp_version);
184 swap_thing (sfheader->sfh_preamble.sfp_flags);
185 swap_thing (sfheader->sfh_cfa_fixed_fp_offset);
186 swap_thing (sfheader->sfh_cfa_fixed_ra_offset);
187 swap_thing (sfheader->sfh_num_fdes);
188 swap_thing (sfheader->sfh_num_fres);
189 swap_thing (sfheader->sfh_fre_len);
190 swap_thing (sfheader->sfh_fdeoff);
191 swap_thing (sfheader->sfh_freoff);
192}
193
194static void
195flip_fde (sframe_func_desc_entry *fdep)
196{
197 swap_thing (fdep->sfde_func_start_address);
198 swap_thing (fdep->sfde_func_size);
199 swap_thing (fdep->sfde_func_start_fre_off);
200 swap_thing (fdep->sfde_func_num_fres);
201}
202
203/* Check if SFrame header has valid data. */
204
205static bool
206sframe_header_sanity_check_p (sframe_header *hp)
207{
208 /* Check preamble is valid. */
209 if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC
210 || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1
211 && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2)
212 || (hp->sfh_preamble.sfp_flags & ~SFRAME_V2_F_ALL_FLAGS))
213 return false;
214
215 /* Check offsets are valid. */
216 if (hp->sfh_fdeoff > hp->sfh_freoff)
217 return false;
218
219 return true;
220}
221
222/* Flip the start address pointed to by FP. */
223
224static void
225flip_fre_start_address (char *addr, uint32_t fre_type)
226{
227 if (fre_type == SFRAME_FRE_TYPE_ADDR2)
228 {
229 uint16_t *start_addr = (uint16_t *)addr;
230 swap_thing (*start_addr);
231 }
232 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
233 {
234 uint32_t *start_addr = (uint32_t *)addr;
235 swap_thing (*start_addr);
236 }
237}
238
239static void
240flip_fre_stack_offsets (char *offsets, uint8_t offset_size, uint8_t offset_cnt)
241{
242 int j;
243
244 if (offset_size == SFRAME_FRE_OFFSET_2B)
245 {
246 uint16_t *ust = (uint16_t *)offsets;
247 for (j = offset_cnt; j > 0; ust++, j--)
248 swap_thing (*ust);
249 }
250 else if (offset_size == SFRAME_FRE_OFFSET_4B)
251 {
252 uint32_t *uit = (uint32_t *)offsets;
253 for (j = offset_cnt; j > 0; uit++, j--)
254 swap_thing (*uit);
255 }
256}
257
258/* Get the FRE start address size, given the FRE_TYPE. */
259
260static size_t
261sframe_fre_start_addr_size (uint32_t fre_type)
262{
263 size_t addr_size = 0;
264 switch (fre_type)
265 {
266 case SFRAME_FRE_TYPE_ADDR1:
267 addr_size = 1;
268 break;
269 case SFRAME_FRE_TYPE_ADDR2:
270 addr_size = 2;
271 break;
272 case SFRAME_FRE_TYPE_ADDR4:
273 addr_size = 4;
274 break;
275 default:
276 /* No other value is expected. */
277 sframe_assert (0);
278 break;
279 }
280 return addr_size;
281}
282
283/* Check if the FREP has valid data. */
284
285static bool
286sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
287{
288 uint8_t offset_size, offset_cnt;
289 uint8_t fre_info;
290
291 if (frep == NULL)
292 return false;
293
294 fre_info = frep->fre_info;
295 offset_size = sframe_fre_get_offset_size (fre_info);
296
297 if (offset_size != SFRAME_FRE_OFFSET_1B
298 && offset_size != SFRAME_FRE_OFFSET_2B
299 && offset_size != SFRAME_FRE_OFFSET_4B)
300 return false;
301
302 offset_cnt = sframe_fre_get_offset_count (fre_info);
303 if (offset_cnt > MAX_NUM_STACK_OFFSETS)
304 return false;
305
306 return true;
307}
308
309/* Get FRE_INFO's offset size in bytes. */
310
311static size_t
312sframe_fre_offset_bytes_size (uint8_t fre_info)
313{
314 uint8_t offset_size, offset_cnt;
315
316 offset_size = sframe_fre_get_offset_size (fre_info);
317
318 debug_printf ("offset_size = %u\n", offset_size);
319
320 offset_cnt = sframe_fre_get_offset_count (fre_info);
321
322 if (offset_size == SFRAME_FRE_OFFSET_2B
323 || offset_size == SFRAME_FRE_OFFSET_4B) /* 2 or 4 bytes. */
324 return (offset_cnt * (offset_size * 2));
325
326 return (offset_cnt);
327}
328
329/* Get total size in bytes to represent FREP in the binary format. This
330 includes the starting address, FRE info, and all the offsets. */
331
332static size_t
333sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
334{
335 if (frep == NULL)
336 return 0;
337
338 uint8_t fre_info = frep->fre_info;
339 size_t addr_size = sframe_fre_start_addr_size (fre_type);
340
341 return (addr_size + sizeof (frep->fre_info)
342 + sframe_fre_offset_bytes_size (fre_info));
343}
344
345/* Get the function descriptor entry at index FUNC_IDX in the decoder
346 context CTX. */
347
348static sframe_func_desc_entry *
349sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
350 uint32_t func_idx)
351{
352 sframe_func_desc_entry *fdep;
353 uint32_t num_fdes;
354 int err;
355
356 num_fdes = sframe_decoder_get_num_fidx (ctx);
357 if (num_fdes == 0
358 || func_idx >= num_fdes
359 || ctx->sfd_funcdesc == NULL)
360 return sframe_ret_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
361
362 fdep = &ctx->sfd_funcdesc[func_idx];
363 return fdep;
364}
365
366/* Get the offset of the start PC of the SFrame FDE at FUNC_IDX from the start
367 of the SFrame section. This section-relative offset is used within
368 libsframe for sorting the SFrame FDEs, and also information lookup routines
369 like sframe_find_fre.
370
371 If FUNC_IDX is not a valid index in the given decoder object, returns 0. */
372
373static int32_t
374sframe_decoder_get_secrel_func_start_addr (sframe_decoder_ctx *dctx,
375 uint32_t func_idx)
376{
377 int err = 0;
378 int32_t offsetof_fde_in_sec
379 = sframe_decoder_get_offsetof_fde_start_addr (dctx, func_idx, &err);
380 /* If func_idx is not a valid index, return 0. */
381 if (err)
382 return 0;
383
384 int32_t func_start_addr = dctx->sfd_funcdesc[func_idx].sfde_func_start_address;
385
386 return func_start_addr + offsetof_fde_in_sec;
387}
388
389/* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
390 the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
391 information for the PC. */
392
393static bool
394sframe_fre_check_range_p (sframe_decoder_ctx *dctx, uint32_t func_idx,
395 uint32_t start_ip_offset, uint32_t end_ip_offset,
396 int32_t pc)
397{
398 sframe_func_desc_entry *fdep;
399 int32_t func_start_addr;
400 uint8_t rep_block_size;
401 uint32_t fde_type;
402 uint32_t pc_offset;
403 bool mask_p;
404
405 fdep = &dctx->sfd_funcdesc[func_idx];
406 func_start_addr = sframe_decoder_get_secrel_func_start_addr (dctx, func_idx);
407 fde_type = sframe_get_fde_type (fdep);
408 mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
409 rep_block_size = fdep->sfde_func_rep_size;
410
411 if (func_start_addr > pc)
412 return false;
413
414 /* Given func_start_addr <= pc, pc - func_start_addr must be positive. */
415 pc_offset = pc - func_start_addr;
416 /* For SFrame FDEs encoding information for repetitive pattern of insns,
417 masking with the rep_block_size is necessary to find the matching FRE. */
418 if (mask_p)
419 pc_offset = pc_offset % rep_block_size;
420
421 return (start_ip_offset <= pc_offset) && (end_ip_offset >= pc_offset);
422}
423
424static int
425flip_fre (char *fp, uint32_t fre_type, size_t *fre_size)
426{
427 uint8_t fre_info;
428 uint8_t offset_size, offset_cnt;
429 size_t addr_size, fre_info_size = 0;
430 int err = 0;
431
432 if (fre_size == NULL)
433 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
434
435 flip_fre_start_address (fp, fre_type);
436
437 /* Advance the buffer pointer to where the FRE info is. */
438 addr_size = sframe_fre_start_addr_size (fre_type);
439 fp += addr_size;
440
441 /* FRE info is uint8_t. No need to flip. */
442 fre_info = *(uint8_t*)fp;
443 offset_size = sframe_fre_get_offset_size (fre_info);
444 offset_cnt = sframe_fre_get_offset_count (fre_info);
445
446 /* Advance the buffer pointer to where the stack offsets are. */
447 fre_info_size = sizeof (uint8_t);
448 fp += fre_info_size;
449 flip_fre_stack_offsets (fp, offset_size, offset_cnt);
450
451 *fre_size
452 = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
453
454 return 0;
455}
456
457/* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
458 The SFrame header in the FRAME_BUF must be endian flipped prior to
459 calling flip_sframe.
460
461 Endian flipping at decode time vs encode time have different needs. At
462 encode time, the frame_buf is in host endianness, and hence, values should
463 be read up before the buffer is changed to foreign endianness. This change
464 of behaviour is specified via TO_FOREIGN arg.
465
466 If an error code is returned, the buffer should not be used. */
467
468static int
469flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign)
470{
471 unsigned int i, j, prev_frep_index;
472 sframe_header *ihp;
473 char *fdes;
474 char *fp = NULL;
475 sframe_func_desc_entry *fdep;
476 unsigned int num_fdes = 0;
477 unsigned int num_fres = 0;
478 uint32_t fre_type = 0;
479 uint32_t fre_offset = 0;
480 size_t esz = 0;
481 size_t hdrsz = 0;
482 int err = 0;
483 /* For error checking. */
484 size_t bytes_flipped = 0;
485
486 /* Header must be in host endianness at this time. */
487 ihp = (sframe_header *)frame_buf;
488
489 if (!sframe_header_sanity_check_p (ihp))
490 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
491
492 /* The contents of the SFrame header are safe to read. Get the number of
493 FDEs and the first FDE in the buffer. */
494 hdrsz = sframe_get_hdr_size (ihp);
495 num_fdes = ihp->sfh_num_fdes;
496 fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
497 fdep = (sframe_func_desc_entry *)fdes;
498
499 j = 0;
500 prev_frep_index = 0;
501 for (i = 0; i < num_fdes; fdep++, i++)
502 {
503 if ((char*)fdep >= (frame_buf + buf_size))
504 goto bad;
505
506 if (to_foreign)
507 {
508 num_fres = fdep->sfde_func_num_fres;
509 fre_type = sframe_get_fre_type (fdep);
510 fre_offset = fdep->sfde_func_start_fre_off;
511 }
512
513 flip_fde (fdep);
514 bytes_flipped += sizeof (sframe_func_desc_entry);
515
516 if (!to_foreign)
517 {
518 num_fres = fdep->sfde_func_num_fres;
519 fre_type = sframe_get_fre_type (fdep);
520 fre_offset = fdep->sfde_func_start_fre_off;
521 }
522
523 fp = frame_buf + sframe_get_hdr_size (ihp) + ihp->sfh_freoff;
524 fp += fre_offset;
525 for (; j < prev_frep_index + num_fres; j++)
526 {
527 if (flip_fre (fp, fre_type, &esz))
528 goto bad;
529 bytes_flipped += esz;
530
531 if (esz == 0 || esz > buf_size)
532 goto bad;
533 fp += esz;
534 }
535 prev_frep_index = j;
536 }
537 /* All FDEs and FREs must have been endian flipped by now. */
538 if ((j != ihp->sfh_num_fres) || (bytes_flipped != (buf_size - hdrsz)))
539 goto bad;
540
541 /* Success. */
542 return 0;
543bad:
544 return SFRAME_ERR;
545}
546
547/* The SFrame Decoder. */
548
549/* Get SFrame header from the given decoder context DCTX. */
550
551static sframe_header *
552sframe_decoder_get_header (sframe_decoder_ctx *dctx)
553{
554 sframe_header *hp = NULL;
555 if (dctx != NULL)
556 hp = &dctx->sfd_header;
557 return hp;
558}
559
560/* Compare function for qsort'ing the FDE table. */
561
562static int
563fde_func (const void *p1, const void *p2)
564{
565 const sframe_func_desc_entry *aa = p1;
566 const sframe_func_desc_entry *bb = p2;
567
568 if (aa->sfde_func_start_address < bb->sfde_func_start_address)
569 return -1;
570 else if (aa->sfde_func_start_address > bb->sfde_func_start_address)
571 return 1;
572 return 0;
573}
574
575/* Get IDX'th offset from FRE. Set errp as applicable. */
576
577static int32_t
578sframe_get_fre_offset (sframe_frame_row_entry *fre, int idx, int *errp)
579{
580 uint8_t offset_cnt, offset_size;
581
582 if (fre == NULL || !sframe_fre_sanity_check_p (fre))
583 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
584
585 offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
586 offset_size = sframe_fre_get_offset_size (fre->fre_info);
587
588 if (offset_cnt < idx + 1)
589 return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
590
591 if (errp)
592 *errp = 0; /* Offset Valid. */
593
594 if (offset_size == SFRAME_FRE_OFFSET_1B)
595 {
596 int8_t *sp = (int8_t *)fre->fre_offsets;
597 return sp[idx];
598 }
599 else if (offset_size == SFRAME_FRE_OFFSET_2B)
600 {
601 int16_t *sp = (int16_t *)fre->fre_offsets;
602 return sp[idx];
603 }
604 else
605 {
606 int32_t *ip = (int32_t *)fre->fre_offsets;
607 return ip[idx];
608 }
609}
610
611/* Free the decoder context. */
612
613void
614sframe_decoder_free (sframe_decoder_ctx **dctxp)
615{
616 if (dctxp != NULL)
617 {
618 sframe_decoder_ctx *dctx = *dctxp;
619 if (dctx == NULL)
620 return;
621
622 if (dctx->sfd_funcdesc != NULL)
623 {
624 free (dctx->sfd_funcdesc);
625 dctx->sfd_funcdesc = NULL;
626 }
627 if (dctx->sfd_fres != NULL)
628 {
629 free (dctx->sfd_fres);
630 dctx->sfd_fres = NULL;
631 }
632 if (dctx->sfd_buf != NULL)
633 {
634 free (dctx->sfd_buf);
635 dctx->sfd_buf = NULL;
636 }
637
638 free (*dctxp);
639 *dctxp = NULL;
640 }
641}
642
643/* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE. */
644/* FIXME API for linker. Revisit if its better placed somewhere else? */
645
646unsigned char
647sframe_fde_create_func_info (uint32_t fre_type,
648 uint32_t fde_type)
649{
650 unsigned char func_info;
651 sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
652 || fre_type == SFRAME_FRE_TYPE_ADDR2
653 || fre_type == SFRAME_FRE_TYPE_ADDR4);
654 sframe_assert (fde_type == SFRAME_FDE_TYPE_PCINC
655 || fde_type == SFRAME_FDE_TYPE_PCMASK);
656 func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
657 return func_info;
658}
659
660/* Get the FRE type given the function size. */
661/* FIXME API for linker. Revisit if its better placed somewhere else? */
662
663uint32_t
664sframe_calc_fre_type (size_t func_size)
665{
666 uint32_t fre_type = 0;
667 if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
668 fre_type = SFRAME_FRE_TYPE_ADDR1;
669 else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
670 fre_type = SFRAME_FRE_TYPE_ADDR2;
671 /* Adjust the check a bit so that it remains warning-free but meaningful
672 on 32-bit systems. */
673 else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1))
674 fre_type = SFRAME_FRE_TYPE_ADDR4;
675 return fre_type;
676}
677
678/* Get the base reg id from the FRE info. Set errp if failure. */
679
680uint8_t
681sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
682{
683 if (fre == NULL)
684 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
685
686 uint8_t fre_info = fre->fre_info;
687 return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
688}
689
690/* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */
691
692int32_t
693sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
694 sframe_frame_row_entry *fre, int *errp)
695{
696 return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
697}
698
699/* Get the FP offset from the FRE. If the offset is invalid, sets errp. */
700
701int32_t
702sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
703 sframe_frame_row_entry *fre, int *errp)
704{
705 uint32_t fp_offset_idx = 0;
706 int8_t fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
707 /* If the FP offset is not being tracked, return the fixed FP offset
708 from the SFrame header. */
709 if (fp_offset != SFRAME_CFA_FIXED_FP_INVALID)
710 {
711 if (errp)
712 *errp = 0;
713 return fp_offset;
714 }
715
716 /* In some ABIs, the stack offset to recover RA (using the CFA) from is
717 fixed (like AMD64). In such cases, the stack offset to recover FP will
718 appear at the second index. */
719 fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
720 != SFRAME_CFA_FIXED_RA_INVALID)
721 ? SFRAME_FRE_RA_OFFSET_IDX
722 : SFRAME_FRE_FP_OFFSET_IDX);
723 return sframe_get_fre_offset (fre, fp_offset_idx, errp);
724}
725
726/* Get the RA offset from the FRE. If the offset is invalid, sets errp. */
727
728int32_t
729sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
730 sframe_frame_row_entry *fre, int *errp)
731{
732 int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
733 /* If the RA offset was not being tracked, return the fixed RA offset
734 from the SFrame header. */
735 if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
736 {
737 if (errp)
738 *errp = 0;
739 return ra_offset;
740 }
741
742 /* Otherwise, get the RA offset from the FRE. */
743 return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
744}
745
746/* Get whether the RA is mangled. */
747
748bool
749sframe_fre_get_ra_mangled_p (sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED,
750 sframe_frame_row_entry *fre, int *errp)
751{
752 if (fre == NULL || !sframe_fre_sanity_check_p (fre))
753 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
754
755 return sframe_get_fre_ra_mangled_p (fre->fre_info);
756}
757
758static int
759sframe_frame_row_entry_copy (sframe_frame_row_entry *dst,
760 sframe_frame_row_entry *src)
761{
762 int err = 0;
763
764 if (dst == NULL || src == NULL)
765 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
766
767 memcpy (dst, src, sizeof (sframe_frame_row_entry));
768 return 0;
769}
770
771/* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
772 binary format, given the FRE_TYPE. Updates the FRE_START_ADDR.
773
774 Returns 0 on success, SFRAME_ERR otherwise. */
775
776static int
777sframe_decode_fre_start_address (const char *fre_buf,
778 uint32_t *fre_start_addr,
779 uint32_t fre_type)
780{
781 uint32_t saddr = 0;
782 int err = 0;
783 size_t addr_size = 0;
784
785 addr_size = sframe_fre_start_addr_size (fre_type);
786
787 if (fre_type == SFRAME_FRE_TYPE_ADDR1)
788 {
789 uint8_t *uc = (uint8_t *)fre_buf;
790 saddr = (uint32_t)*uc;
791 }
792 else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
793 {
794 uint16_t *ust = (uint16_t *)fre_buf;
795 /* SFrame is an unaligned on-disk format. Using memcpy helps avoid the
796 use of undesirable unaligned loads. See PR libsframe/29856. */
797 uint16_t tmp = 0;
798 memcpy (&tmp, ust, addr_size);
799 saddr = (uint32_t)tmp;
800 }
801 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
802 {
803 uint32_t *uit = (uint32_t *)fre_buf;
804 uint32_t tmp = 0;
805 memcpy (&tmp, uit, addr_size);
806 saddr = (uint32_t)tmp;
807 }
808 else
809 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
810
811 *fre_start_addr = saddr;
812 return 0;
813}
814
815/* Decode a frame row entry FRE which starts at location FRE_BUF. The function
816 updates ESZ to the size of the FRE as stored in the binary format.
817
818 This function works closely with the SFrame binary format.
819
820 Returns SFRAME_ERR if failure. */
821
822static int
823sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
824 uint32_t fre_type, size_t *esz)
825{
826 int err = 0;
827 const char *stack_offsets = NULL;
828 size_t stack_offsets_sz;
829 size_t addr_size;
830 size_t fre_size;
831
832 if (fre_buf == NULL || fre == NULL || esz == NULL)
833 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
834
835 /* Copy over the FRE start address. */
836 sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
837
838 addr_size = sframe_fre_start_addr_size (fre_type);
839 fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
840 /* Sanity check as the API works closely with the binary format. */
841 sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
842
843 /* Cleanup the space for fre_offsets first, then copy over the valid
844 bytes. */
845 memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
846 /* Get offsets size. */
847 stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
848 stack_offsets = fre_buf + addr_size + sizeof (fre->fre_info);
849 memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
850
851 /* The FRE has been decoded. Use it to perform one last sanity check. */
852 fre_size = sframe_fre_entry_size (fre, fre_type);
853 sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
854 + stack_offsets_sz));
855 *esz = fre_size;
856
857 return 0;
858}
859
860/* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
861 new SFrame decoder context.
862
863 Sets ERRP for the caller if any error. Frees up the allocated memory in
864 case of error. */
865
866sframe_decoder_ctx *
867sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
868{
869 const sframe_preamble *sfp;
870 size_t hdrsz;
871 sframe_header *sfheaderp;
872 sframe_decoder_ctx *dctx;
873 char *frame_buf;
874 char *tempbuf = NULL;
875
876 int fidx_size;
877 uint32_t fre_bytes;
878 int foreign_endian = 0;
879
880 sframe_init_debug ();
881
882 if ((sf_buf == NULL) || (!sf_size))
883 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
884 else if (sf_size < sizeof (sframe_header))
885 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
886
887 sfp = (const sframe_preamble *) sf_buf;
888
889 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
890 sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
891
892 /* Check for foreign endianness. */
893 if (sfp->sfp_magic != SFRAME_MAGIC)
894 {
895 if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
896 foreign_endian = 1;
897 else
898 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
899 }
900
901 /* Initialize a new decoder context. */
902 if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
903 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
904 memset (dctx, 0, sizeof (sframe_decoder_ctx));
905
906 if (foreign_endian)
907 {
908 /* Allocate a new buffer and initialize it. */
909 tempbuf = (char *) malloc (sf_size * sizeof (char));
910 if (tempbuf == NULL)
911 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
912 memcpy (tempbuf, sf_buf, sf_size);
913
914 /* Flip the header. */
915 sframe_header *ihp = (sframe_header *) tempbuf;
916 flip_header (ihp);
917 /* Flip the rest of the SFrame section data buffer. */
918 if (flip_sframe (tempbuf, sf_size, 0))
919 {
920 free (tempbuf);
921 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
922 }
923 frame_buf = tempbuf;
924 /* This buffer is malloc'd when endian flipping the contents of the input
925 buffer are needed. Keep a reference to it so it can be free'd up
926 later in sframe_decoder_free (). */
927 dctx->sfd_buf = tempbuf;
928 }
929 else
930 frame_buf = (char *)sf_buf;
931
932 /* Handle the SFrame header. */
933 dctx->sfd_header = *(sframe_header *) frame_buf;
934 /* Validate the contents of SFrame header. */
935 sfheaderp = &dctx->sfd_header;
936 if (!sframe_header_sanity_check_p (sfheaderp))
937 {
938 sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
939 goto decode_fail_free;
940 }
941 hdrsz = sframe_get_hdr_size (sfheaderp);
942 frame_buf += hdrsz;
943
944 /* Handle the SFrame Function Descriptor Entry section. */
945 fidx_size
946 = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
947 dctx->sfd_funcdesc = malloc (fidx_size);
948 if (dctx->sfd_funcdesc == NULL)
949 {
950 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
951 goto decode_fail_free;
952 }
953 memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
954
955 debug_printf ("%u total fidx size\n", fidx_size);
956
957 frame_buf += (fidx_size);
958
959 /* Handle the SFrame Frame Row Entry section. */
960 dctx->sfd_fres = (char *) malloc (sfheaderp->sfh_fre_len);
961 if (dctx->sfd_fres == NULL)
962 {
963 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
964 goto decode_fail_free;
965 }
966 memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
967
968 fre_bytes = sfheaderp->sfh_fre_len;
969 dctx->sfd_fre_nbytes = fre_bytes;
970
971 debug_printf ("%u total fre bytes\n", fre_bytes);
972
973 return dctx;
974
975decode_fail_free:
976 if (foreign_endian && tempbuf != NULL)
977 free (tempbuf);
978 sframe_decoder_free (&dctx);
979 dctx = NULL;
980 return dctx;
981}
982
983/* Get the size of the SFrame header from the decoder context CTX. */
984
985unsigned int
986sframe_decoder_get_hdr_size (sframe_decoder_ctx *ctx)
987{
988 sframe_header *dhp;
989 dhp = sframe_decoder_get_header (ctx);
990 return sframe_get_hdr_size (dhp);
991}
992
993/* Get the SFrame's abi/arch info given the decoder context DCTX. */
994
995uint8_t
996sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx)
997{
998 sframe_header *sframe_header;
999 sframe_header = sframe_decoder_get_header (dctx);
1000 return sframe_header->sfh_abi_arch;
1001}
1002
1003/* Get the format version from the SFrame decoder context DCTX. */
1004
1005uint8_t
1006sframe_decoder_get_version (sframe_decoder_ctx *dctx)
1007{
1008 sframe_header *dhp;
1009 dhp = sframe_decoder_get_header (dctx);
1010 return dhp->sfh_preamble.sfp_version;
1011}
1012
1013/* Get the section flags from the SFrame decoder context DCTX. */
1014
1015uint8_t
1016sframe_decoder_get_flags (sframe_decoder_ctx *dctx)
1017{
1018 const sframe_header *dhp = sframe_decoder_get_header (dctx);
1019 return dhp->sfh_preamble.sfp_flags;
1020}
1021
1022/* Get the SFrame's fixed FP offset given the decoder context CTX. */
1023int8_t
1024sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
1025{
1026 sframe_header *dhp;
1027 dhp = sframe_decoder_get_header (ctx);
1028 return dhp->sfh_cfa_fixed_fp_offset;
1029}
1030
1031/* Get the SFrame's fixed RA offset given the decoder context CTX. */
1032int8_t
1033sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
1034{
1035 sframe_header *dhp;
1036 dhp = sframe_decoder_get_header (ctx);
1037 return dhp->sfh_cfa_fixed_ra_offset;
1038}
1039
1040/* Get the offset of the sfde_func_start_address field (from the start of the
1041 on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the decoder
1042 context DCTX.
1043
1044 If FUNC_IDX is more than the number of SFrame FDEs in the section, sets
1045 error code in ERRP, but returns the (hypothetical) offset. This is useful
1046 for the linker when arranging input FDEs into the output section to be
1047 emitted. */
1048
1049uint32_t
1050sframe_decoder_get_offsetof_fde_start_addr (sframe_decoder_ctx *dctx,
1051 uint32_t func_idx, int *errp)
1052{
1053 if (func_idx >= sframe_decoder_get_num_fidx (dctx))
1054 sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
1055 else if (errp)
1056 *errp = 0;
1057
1058 return (sframe_decoder_get_hdr_size (dctx)
1059 + func_idx * sizeof (sframe_func_desc_entry)
1060 + offsetof (sframe_func_desc_entry, sfde_func_start_address));
1061}
1062
1063/* Find the function descriptor entry which contains the specified address
1064 ADDR.
1065 This function is deprecated and will be removed from libsframe.so.2. */
1066
1067void *
1068sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx __attribute__ ((unused)),
1069 int32_t addr __attribute__ ((unused)),
1070 int *errp)
1071{
1072 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1073}
1074
1075/* Find the function descriptor entry starting which contains the specified
1076 address ADDR. */
1077
1078static sframe_func_desc_entry *
1079sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr,
1080 int *errp, uint32_t *func_idx)
1081{
1082 sframe_header *dhp;
1083 sframe_func_desc_entry *fdp;
1084 int low, high;
1085
1086 if (ctx == NULL)
1087 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1088
1089 dhp = sframe_decoder_get_header (ctx);
1090
1091 if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
1092 return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL);
1093 /* If the FDE sub-section is not sorted on PCs, skip the lookup because
1094 binary search cannot be used. */
1095 if ((sframe_decoder_get_flags (ctx) & SFRAME_F_FDE_SORTED) == 0)
1096 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED);
1097
1098 /* Do the binary search. */
1099 fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
1100 low = 0;
1101 high = dhp->sfh_num_fdes - 1;
1102 while (low <= high)
1103 {
1104 int mid = low + (high - low) / 2;
1105
1106 /* Given sfde_func_start_address <= addr,
1107 addr - sfde_func_start_address must be positive. */
1108 if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) <= addr
1109 && ((uint32_t)(addr - sframe_decoder_get_secrel_func_start_addr (ctx,
1110 mid))
1111 < fdp[mid].sfde_func_size))
1112 {
1113 *func_idx = mid;
1114 return fdp + mid;
1115 }
1116
1117 if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) < addr)
1118 low = mid + 1;
1119 else
1120 high = mid - 1;
1121 }
1122
1123 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
1124}
1125
1126/* Get the end IP offset for the FRE at index i in the FDEP. The buffer FRES
1127 is the starting location for the FRE. */
1128
1129static uint32_t
1130sframe_fre_get_end_ip_offset (sframe_func_desc_entry *fdep, unsigned int i,
1131 const char *fres)
1132{
1133 uint32_t end_ip_offset;
1134 uint32_t fre_type;
1135
1136 fre_type = sframe_get_fre_type (fdep);
1137
1138 /* Get the start address of the next FRE in sequence. */
1139 if (i < fdep->sfde_func_num_fres - 1)
1140 {
1141 sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
1142 end_ip_offset -= 1;
1143 }
1144 else
1145 /* The end IP offset for the FRE needs to be deduced from the function
1146 size. */
1147 end_ip_offset = fdep->sfde_func_size - 1;
1148
1149 return end_ip_offset;
1150}
1151
1152/* Find the SFrame Row Entry which contains the PC. Returns
1153 SFRAME_ERR if failure. */
1154
1155int
1156sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
1157 sframe_frame_row_entry *frep)
1158{
1159 sframe_frame_row_entry cur_fre;
1160 sframe_func_desc_entry *fdep;
1161 uint32_t func_idx;
1162 uint32_t fre_type, i;
1163 int32_t func_start_addr;
1164 uint32_t start_ip_offset, end_ip_offset;
1165 const char *fres;
1166 size_t size = 0;
1167 int err = 0;
1168
1169 if ((ctx == NULL) || (frep == NULL))
1170 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1171
1172 /* Find the FDE which contains the PC, then scan its fre entries. */
1173 fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err, &func_idx);
1174 if (fdep == NULL || ctx->sfd_fres == NULL)
1175 return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL);
1176
1177 fre_type = sframe_get_fre_type (fdep);
1178
1179 fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1180 func_start_addr = sframe_decoder_get_secrel_func_start_addr (ctx, func_idx);
1181
1182 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1183 {
1184 err = sframe_decode_fre (fres, &cur_fre, fre_type, &size);
1185 if (err)
1186 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1187
1188 start_ip_offset = cur_fre.fre_start_addr;
1189 end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
1190
1191 /* Stop search if FRE's start_ip is greater than pc. Given
1192 func_start_addr <= pc, pc - func_start_addr must be positive. */
1193 if (start_ip_offset > (uint32_t)(pc - func_start_addr))
1194 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1195
1196 if (sframe_fre_check_range_p (ctx, func_idx, start_ip_offset,
1197 end_ip_offset, pc))
1198 {
1199 sframe_frame_row_entry_copy (frep, &cur_fre);
1200 return 0;
1201 }
1202 fres += size;
1203 }
1204 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1205}
1206
1207/* Return the number of function descriptor entries in the SFrame decoder
1208 DCTX. */
1209
1210uint32_t
1211sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
1212{
1213 uint32_t num_fdes = 0;
1214 sframe_header *dhp = NULL;
1215 dhp = sframe_decoder_get_header (ctx);
1216 if (dhp)
1217 num_fdes = dhp->sfh_num_fdes;
1218 return num_fdes;
1219}
1220
1221/* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
1222 descriptor entry at index I'th in the decoder CTX. If failed,
1223 return error code. */
1224/* FIXME - consolidate the args and return a
1225 sframe_func_desc_index_elem rather? */
1226
1227int
1228sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
1229 unsigned int i,
1230 uint32_t *num_fres,
1231 uint32_t *func_size,
1232 int32_t *func_start_address,
1233 unsigned char *func_info)
1234{
1235 sframe_func_desc_entry *fdp;
1236 int err = 0;
1237
1238 if (ctx == NULL || func_start_address == NULL || num_fres == NULL
1239 || func_size == NULL)
1240 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1241
1242 fdp = sframe_decoder_get_funcdesc_at_index (ctx, i);
1243
1244 if (fdp == NULL)
1245 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1246
1247 *num_fres = fdp->sfde_func_num_fres;
1248 *func_start_address = fdp->sfde_func_start_address;
1249 *func_size = fdp->sfde_func_size;
1250 *func_info = fdp->sfde_func_info;
1251
1252 return 0;
1253}
1254
1255int
1256sframe_decoder_get_funcdesc_v2 (sframe_decoder_ctx *dctx,
1257 unsigned int i,
1258 uint32_t *num_fres,
1259 uint32_t *func_size,
1260 int32_t *func_start_address,
1261 unsigned char *func_info,
1262 uint8_t *rep_block_size)
1263{
1264 sframe_func_desc_entry *fdp;
1265 int err = 0;
1266
1267 if (dctx == NULL || func_start_address == NULL
1268 || num_fres == NULL || func_size == NULL
1269 || sframe_decoder_get_version (dctx) == SFRAME_VERSION_1)
1270 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1271
1272 fdp = sframe_decoder_get_funcdesc_at_index (dctx, i);
1273
1274 if (fdp == NULL)
1275 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1276
1277 *num_fres = fdp->sfde_func_num_fres;
1278 *func_start_address = fdp->sfde_func_start_address;
1279 *func_size = fdp->sfde_func_size;
1280 *func_info = fdp->sfde_func_info;
1281 *rep_block_size = fdp->sfde_func_rep_size;
1282
1283 return 0;
1284}
1285/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
1286 descriptor entry in the SFrame decoder CTX. Returns error code as
1287 applicable. */
1288
1289int
1290sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
1291 unsigned int func_idx,
1292 unsigned int fre_idx,
1293 sframe_frame_row_entry *fre)
1294{
1295 sframe_func_desc_entry *fdep;
1296 sframe_frame_row_entry ifre;
1297 const char *fres;
1298 uint32_t i;
1299 uint32_t fre_type;
1300 size_t esz = 0;
1301 int err = 0;
1302
1303 if (ctx == NULL || fre == NULL)
1304 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1305
1306 /* Get function descriptor entry at index func_idx. */
1307 fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
1308
1309 if (fdep == NULL)
1310 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1311
1312 fre_type = sframe_get_fre_type (fdep);
1313 /* Now scan the FRE entries. */
1314 fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
1315 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1316 {
1317 /* Decode the FRE at the current position. Return it if valid. */
1318 err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
1319 if (i == fre_idx)
1320 {
1321 if (!sframe_fre_sanity_check_p (&ifre))
1322 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1323
1324 sframe_frame_row_entry_copy (fre, &ifre);
1325
1326 if (fdep->sfde_func_size)
1327 sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
1328 else
1329 /* A SFrame FDE with func size equal to zero is possible. */
1330 sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
1331
1332 return 0;
1333 }
1334 /* Next FRE. */
1335 fres += esz;
1336 }
1337
1338 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1339}
1340
1341
1342/* SFrame Encoder. */
1343
1344/* Get a reference to the ENCODER's SFrame header. */
1345
1346static sframe_header *
1347sframe_encoder_get_header (sframe_encoder_ctx *encoder)
1348{
1349 sframe_header *hp = NULL;
1350 if (encoder)
1351 hp = &encoder->sfe_header;
1352 return hp;
1353}
1354
1355static sframe_func_desc_entry *
1356sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
1357 uint32_t func_idx)
1358{
1359 sframe_func_desc_entry *fde = NULL;
1360 if (func_idx < sframe_encoder_get_num_fidx (encoder))
1361 {
1362 sf_fde_tbl *func_tbl = encoder->sfe_funcdesc;
1363 fde = func_tbl->entry + func_idx;
1364 }
1365 return fde;
1366}
1367
1368/* Create an encoder context with the given SFrame format version VER, FLAGS
1369 and ABI information. Uses the ABI specific FIXED_FP_OFFSET and
1370 FIXED_RA_OFFSET values as provided. Sets errp if failure. */
1371
1372sframe_encoder_ctx *
1373sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
1374 int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
1375{
1376 sframe_header *hp;
1377 sframe_encoder_ctx *encoder;
1378
1379 if (ver != SFRAME_VERSION)
1380 return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
1381
1382 if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
1383 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1384
1385 memset (encoder, 0, sizeof (sframe_encoder_ctx));
1386
1387 /* Get the SFrame header and update it. */
1388 hp = sframe_encoder_get_header (encoder);
1389 hp->sfh_preamble.sfp_version = ver;
1390 hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
1391 hp->sfh_preamble.sfp_flags = flags;
1392
1393 /* Implementation in the SFrame encoder APIs, e.g.,
1394 sframe_encoder_write_sframe assume flag SFRAME_F_FDE_FUNC_START_PCREL
1395 set. */
1396 if (!(flags & SFRAME_F_FDE_FUNC_START_PCREL))
1397 return sframe_ret_set_errno (errp, SFRAME_ERR_ECTX_INVAL);
1398
1399 hp->sfh_abi_arch = abi_arch;
1400 hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
1401 hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
1402
1403 return encoder;
1404}
1405
1406/* Free the encoder context. */
1407
1408void
1409sframe_encoder_free (sframe_encoder_ctx **encoder)
1410{
1411 if (encoder != NULL)
1412 {
1413 sframe_encoder_ctx *ectx = *encoder;
1414 if (ectx == NULL)
1415 return;
1416
1417 if (ectx->sfe_funcdesc != NULL)
1418 {
1419 free (ectx->sfe_funcdesc);
1420 ectx->sfe_funcdesc = NULL;
1421 }
1422 if (ectx->sfe_fres != NULL)
1423 {
1424 free (ectx->sfe_fres);
1425 ectx->sfe_fres = NULL;
1426 }
1427 if (ectx->sfe_data != NULL)
1428 {
1429 free (ectx->sfe_data);
1430 ectx->sfe_data = NULL;
1431 }
1432
1433 free (*encoder);
1434 *encoder = NULL;
1435 }
1436}
1437
1438/* Get the size of the SFrame header from the encoder ctx ENCODER. */
1439
1440unsigned int
1441sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
1442{
1443 sframe_header *ehp;
1444 ehp = sframe_encoder_get_header (encoder);
1445 return sframe_get_hdr_size (ehp);
1446}
1447
1448/* Get the abi/arch info from the SFrame encoder context ENCODER. */
1449
1450uint8_t
1451sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
1452{
1453 uint8_t abi_arch = 0;
1454 sframe_header *ehp;
1455 ehp = sframe_encoder_get_header (encoder);
1456 if (ehp)
1457 abi_arch = ehp->sfh_abi_arch;
1458 return abi_arch;
1459}
1460
1461/* Get the format version from the SFrame encoder context ENCODER. */
1462
1463uint8_t
1464sframe_encoder_get_version (sframe_encoder_ctx *encoder)
1465{
1466 sframe_header *ehp;
1467 ehp = sframe_encoder_get_header (encoder);
1468 return ehp->sfh_preamble.sfp_version;
1469}
1470
1471/* Get the section flags from the SFrame encoder context ENCODER. */
1472
1473uint8_t
1474sframe_encoder_get_flags (sframe_encoder_ctx *encoder)
1475{
1476 const sframe_header *ehp = sframe_encoder_get_header (encoder);
1477 return ehp->sfh_preamble.sfp_flags;
1478}
1479
1480/* Return the number of function descriptor entries in the SFrame encoder
1481 ENCODER. */
1482
1483uint32_t
1484sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
1485{
1486 uint32_t num_fdes = 0;
1487 sframe_header *ehp = NULL;
1488 ehp = sframe_encoder_get_header (encoder);
1489 if (ehp)
1490 num_fdes = ehp->sfh_num_fdes;
1491 return num_fdes;
1492}
1493
1494/* Get the offset of the sfde_func_start_address field (from the start of the
1495 on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the encoder
1496 context ENCODER.
1497
1498 If FUNC_IDX is more than the number of SFrame FDEs in the section, sets
1499 error code in ERRP, but returns the (hypothetical) offset. This is useful
1500 for the linker when arranging input FDEs into the output section to be
1501 emitted. */
1502
1503uint32_t
1504sframe_encoder_get_offsetof_fde_start_addr (sframe_encoder_ctx *encoder,
1505 uint32_t func_idx, int *errp)
1506{
1507 if (func_idx >= sframe_encoder_get_num_fidx (encoder))
1508 sframe_ret_set_errno (errp, SFRAME_ERR_FDE_INVAL);
1509 else if (errp)
1510 *errp = 0;
1511
1512 return (sframe_encoder_get_hdr_size (encoder)
1513 + func_idx * sizeof (sframe_func_desc_entry)
1514 + offsetof (sframe_func_desc_entry, sfde_func_start_address));
1515}
1516
1517/* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1518 the encoder context. */
1519
1520int
1521sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
1522 unsigned int func_idx,
1523 sframe_frame_row_entry *frep)
1524{
1525 sframe_header *ehp;
1526 sframe_func_desc_entry *fdep;
1527 sframe_frame_row_entry *ectx_frep;
1528 size_t offsets_sz, esz;
1529 uint32_t fre_type;
1530 size_t fre_tbl_sz;
1531 int err = 0;
1532
1533 if (encoder == NULL || frep == NULL)
1534 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1535 if (!sframe_fre_sanity_check_p (frep))
1536 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1537
1538 /* Use func_idx to gather the function descriptor entry. */
1539 fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
1540
1541 if (fdep == NULL)
1542 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1543
1544 fre_type = sframe_get_fre_type (fdep);
1545 sf_fre_tbl *fre_tbl = encoder->sfe_fres;
1546
1547 if (fre_tbl == NULL)
1548 {
1549 fre_tbl_sz = (sizeof (sf_fre_tbl)
1550 + (number_of_entries * sizeof (sframe_frame_row_entry)));
1551 fre_tbl = malloc (fre_tbl_sz);
1552
1553 if (fre_tbl == NULL)
1554 {
1555 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1556 goto bad; /* OOM. */
1557 }
1558 memset (fre_tbl, 0, fre_tbl_sz);
1559 fre_tbl->alloced = number_of_entries;
1560 }
1561 else if (fre_tbl->count == fre_tbl->alloced)
1562 {
1563 fre_tbl_sz = (sizeof (sf_fre_tbl)
1564 + ((fre_tbl->alloced + number_of_entries)
1565 * sizeof (sframe_frame_row_entry)));
1566 fre_tbl = realloc (fre_tbl, fre_tbl_sz);
1567 if (fre_tbl == NULL)
1568 {
1569 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1570 goto bad; /* OOM. */
1571 }
1572
1573 memset (&fre_tbl->entry[fre_tbl->alloced], 0,
1574 number_of_entries * sizeof (sframe_frame_row_entry));
1575 fre_tbl->alloced += number_of_entries;
1576 }
1577
1578 ectx_frep = &fre_tbl->entry[fre_tbl->count];
1579 ectx_frep->fre_start_addr
1580 = frep->fre_start_addr;
1581 ectx_frep->fre_info = frep->fre_info;
1582
1583 if (fdep->sfde_func_size)
1584 sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
1585 else
1586 /* A SFrame FDE with func size equal to zero is possible. */
1587 sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
1588
1589 /* frep has already been sanity check'd. Get offsets size. */
1590 offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1591 memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
1592
1593 esz = sframe_fre_entry_size (frep, fre_type);
1594 fre_tbl->count++;
1595
1596 encoder->sfe_fres = fre_tbl;
1597 encoder->sfe_fre_nbytes += esz;
1598
1599 ehp = sframe_encoder_get_header (encoder);
1600 ehp->sfh_num_fres = fre_tbl->count;
1601
1602 /* Update the value of the number of FREs for the function. */
1603 fdep->sfde_func_num_fres++;
1604
1605 return 0;
1606
1607bad:
1608 if (fre_tbl != NULL)
1609 free (fre_tbl);
1610 encoder->sfe_fres = NULL;
1611 encoder->sfe_fre_nbytes = 0;
1612 return -1;
1613}
1614
1615/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1616 to the encoder. */
1617
1618int
1619sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
1620 int32_t start_addr,
1621 uint32_t func_size,
1622 unsigned char func_info,
1623 uint32_t num_fres __attribute__ ((unused)))
1624{
1625 sframe_header *ehp;
1626 sf_fde_tbl *fd_info;
1627 size_t fd_tbl_sz;
1628 int err = 0;
1629
1630 /* FIXME book-keep num_fres for error checking. */
1631 if (encoder == NULL)
1632 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1633
1634 fd_info = encoder->sfe_funcdesc;
1635 ehp = sframe_encoder_get_header (encoder);
1636
1637 if (fd_info == NULL)
1638 {
1639 fd_tbl_sz = (sizeof (sf_fde_tbl)
1640 + (number_of_entries * sizeof (sframe_func_desc_entry)));
1641 fd_info = malloc (fd_tbl_sz);
1642 if (fd_info == NULL)
1643 {
1644 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1645 goto bad; /* OOM. */
1646 }
1647 memset (fd_info, 0, fd_tbl_sz);
1648 fd_info->alloced = number_of_entries;
1649 }
1650 else if (fd_info->count == fd_info->alloced)
1651 {
1652 fd_tbl_sz = (sizeof (sf_fde_tbl)
1653 + ((fd_info->alloced + number_of_entries)
1654 * sizeof (sframe_func_desc_entry)));
1655 fd_info = realloc (fd_info, fd_tbl_sz);
1656 if (fd_info == NULL)
1657 {
1658 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1659 goto bad; /* OOM. */
1660 }
1661
1662 memset (&fd_info->entry[fd_info->alloced], 0,
1663 number_of_entries * sizeof (sframe_func_desc_entry));
1664 fd_info->alloced += number_of_entries;
1665 }
1666
1667 fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
1668 /* Num FREs is updated as FREs are added for the function later via
1669 sframe_encoder_add_fre. */
1670 fd_info->entry[fd_info->count].sfde_func_size = func_size;
1671 fd_info->entry[fd_info->count].sfde_func_start_fre_off
1672 = encoder->sfe_fre_nbytes;
1673#if 0
1674 // Linker optimization test code cleanup later ibhagat TODO FIXME
1675 uint32_t fre_type = sframe_calc_fre_type (func_size);
1676
1677 fd_info->entry[fd_info->count].sfde_func_info
1678 = sframe_fde_func_info (fre_type);
1679#endif
1680 fd_info->entry[fd_info->count].sfde_func_info = func_info;
1681 fd_info->count++;
1682 encoder->sfe_funcdesc = fd_info;
1683 ehp->sfh_num_fdes++;
1684 return 0;
1685
1686bad:
1687 if (fd_info != NULL)
1688 free (fd_info);
1689 encoder->sfe_funcdesc = NULL;
1690 ehp->sfh_num_fdes = 0;
1691 return -1;
1692}
1693
1694/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE, FUNC_INFO
1695 and REP_BLOCK_SIZE to the encoder.
1696
1697 This API is valid only for SFrame format version 2. */
1698
1699int
1700sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *encoder,
1701 int32_t start_addr,
1702 uint32_t func_size,
1703 unsigned char func_info,
1704 uint8_t rep_block_size,
1705 uint32_t num_fres __attribute__ ((unused)))
1706{
1707 sf_fde_tbl *fd_info;
1708 int err;
1709
1710 if (encoder == NULL
1711 || sframe_encoder_get_version (encoder) == SFRAME_VERSION_1)
1712 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1713
1714 err = sframe_encoder_add_funcdesc (encoder, start_addr, func_size, func_info,
1715 num_fres);
1716 if (err)
1717 return SFRAME_ERR;
1718
1719 fd_info = encoder->sfe_funcdesc;
1720 fd_info->entry[fd_info->count-1].sfde_func_rep_size = rep_block_size;
1721
1722 return 0;
1723}
1724
1725static int
1726sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
1727{
1728 sframe_header *ehp = sframe_encoder_get_header (encoder);
1729
1730 /* Sort and write out the FDE table. */
1731 sf_fde_tbl *fd_info = encoder->sfe_funcdesc;
1732 if (fd_info)
1733 {
1734 /* The new encoding of sfde_func_start_address means the distances are
1735 not from the same anchor, so cannot be sorted directly. At the moment
1736 we adress this by manual value adjustments before and after sorting.
1737 FIXME - qsort_r may be more optimal. */
1738
1739 for (unsigned int i = 0; i < fd_info->count; i++)
1740 fd_info->entry[i].sfde_func_start_address
1741 += sframe_encoder_get_offsetof_fde_start_addr (encoder, i, NULL);
1742
1743 qsort (fd_info->entry, fd_info->count,
1744 sizeof (sframe_func_desc_entry), fde_func);
1745
1746 for (unsigned int i = 0; i < fd_info->count; i++)
1747 fd_info->entry[i].sfde_func_start_address
1748 -= sframe_encoder_get_offsetof_fde_start_addr (encoder, i, NULL);
1749
1750 /* Update preamble's flags. */
1751 ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
1752 }
1753 return 0;
1754}
1755
1756/* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1757 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1758 FRE_START_ADDR_SZ. */
1759
1760static int
1761sframe_encoder_write_fre_start_addr (char *contents,
1762 uint32_t fre_start_addr,
1763 uint32_t fre_type,
1764 size_t fre_start_addr_sz)
1765{
1766 int err = 0;
1767
1768 if (fre_type == SFRAME_FRE_TYPE_ADDR1)
1769 {
1770 uint8_t uc = fre_start_addr;
1771 memcpy (contents, &uc, fre_start_addr_sz);
1772 }
1773 else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
1774 {
1775 uint16_t ust = fre_start_addr;
1776 memcpy (contents, &ust, fre_start_addr_sz);
1777 }
1778 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
1779 {
1780 uint32_t uit = fre_start_addr;
1781 memcpy (contents, &uit, fre_start_addr_sz);
1782 }
1783 else
1784 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1785
1786 return 0;
1787}
1788
1789/* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1790 size in bytes written out are updated in ESZ.
1791
1792 This function works closely with the SFrame binary format.
1793
1794 Returns SFRAME_ERR if failure. */
1795
1796static int
1797sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
1798 uint32_t fre_type, size_t *esz)
1799{
1800 size_t fre_sz;
1801 size_t fre_start_addr_sz;
1802 size_t fre_stack_offsets_sz;
1803 int err = 0;
1804
1805 if (!sframe_fre_sanity_check_p (frep))
1806 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1807
1808 fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
1809 fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1810
1811 /* The FRE start address must be encodable in the available number of
1812 bytes. */
1813 uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
1814 sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
1815
1816 sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
1817 fre_type, fre_start_addr_sz);
1818 contents += fre_start_addr_sz;
1819
1820 memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
1821 contents += sizeof (frep->fre_info);
1822
1823 memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
1824 contents+= fre_stack_offsets_sz;
1825
1826 fre_sz = sframe_fre_entry_size (frep, fre_type);
1827 /* Sanity checking. */
1828 sframe_assert ((fre_start_addr_sz
1829 + sizeof (frep->fre_info)
1830 + fre_stack_offsets_sz) == fre_sz);
1831
1832 *esz = fre_sz;
1833
1834 return 0;
1835}
1836
1837/* Serialize the core contents of the SFrame section and write out to the
1838 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1839
1840static int
1841sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
1842{
1843 char *contents;
1844 size_t buf_size;
1845 size_t hdr_size;
1846 size_t all_fdes_size;
1847 size_t fre_size;
1848 size_t esz = 0;
1849 sframe_header *ehp;
1850 sf_fde_tbl *fd_info;
1851 sf_fre_tbl *fr_info;
1852 uint32_t i, num_fdes;
1853 uint32_t j, num_fres;
1854 sframe_func_desc_entry *fdep;
1855 sframe_frame_row_entry *frep;
1856
1857 uint32_t fre_type;
1858 int err = 0;
1859
1860 contents = encoder->sfe_data;
1861 buf_size = encoder->sfe_data_size;
1862 num_fdes = sframe_encoder_get_num_fidx (encoder);
1863 all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
1864 ehp = sframe_encoder_get_header (encoder);
1865 hdr_size = sframe_get_hdr_size (ehp);
1866
1867 fd_info = encoder->sfe_funcdesc;
1868 fr_info = encoder->sfe_fres;
1869
1870 /* Sanity checks:
1871 - buffers must be malloc'd by the caller. */
1872 if ((contents == NULL) || (buf_size < hdr_size))
1873 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
1874 if (fr_info == NULL)
1875 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1876
1877 /* Write out the FRE table first.
1878
1879 Recall that read/write of FREs needs information from the corresponding
1880 FDE; the latter stores the information about the FRE type record used for
1881 the function. Also note that sorting of FDEs does NOT impact the order
1882 in which FREs are stored in the SFrame's FRE sub-section. This means
1883 that writing out FREs after sorting of FDEs will need some additional
1884 book-keeping. At this time, we can afford to avoid it by writing out
1885 the FREs first to the output buffer. */
1886 fre_size = 0;
1887 uint32_t global = 0;
1888 uint32_t fre_index = 0;
1889
1890 contents += hdr_size + all_fdes_size;
1891 for (i = 0; i < num_fdes; i++)
1892 {
1893 fdep = &fd_info->entry[i];
1894 fre_type = sframe_get_fre_type (fdep);
1895 num_fres = fdep->sfde_func_num_fres;
1896
1897 for (j = 0; j < num_fres; j++)
1898 {
1899 fre_index = global + j;
1900 frep = &fr_info->entry[fre_index];
1901
1902 sframe_encoder_write_fre (contents, frep, fre_type, &esz);
1903 contents += esz;
1904 fre_size += esz; /* For debugging only. */
1905 }
1906 global += j;
1907 }
1908
1909 sframe_assert (fre_size == ehp->sfh_fre_len);
1910 sframe_assert (global == ehp->sfh_num_fres);
1911 sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
1912
1913 /* Sort the FDE table */
1914 sframe_sort_funcdesc (encoder);
1915
1916 /* Sanity checks:
1917 - the FDE section must have been sorted by now on the start address
1918 of each function. */
1919 if (!(sframe_encoder_get_flags (encoder) & SFRAME_F_FDE_SORTED)
1920 || (fd_info == NULL))
1921 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1922
1923 contents = encoder->sfe_data;
1924 /* Write out the SFrame header. The SFrame header in the encoder
1925 object has already been updated with correct offsets by the caller. */
1926 memcpy (contents, ehp, hdr_size);
1927 contents += hdr_size;
1928
1929 /* Write out the FDE table sorted on funtion start address. */
1930 memcpy (contents, fd_info->entry, all_fdes_size);
1931 contents += all_fdes_size;
1932
1933 return 0;
1934}
1935
1936/* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1937 is updated to the size of the buffer. */
1938
1939char *
1940sframe_encoder_write (sframe_encoder_ctx *encoder,
1941 size_t *encoded_size, int *errp)
1942{
1943 sframe_header *ehp;
1944 size_t hdrsize, fsz, fresz, bufsize;
1945 int foreign_endian;
1946
1947 /* Initialize the encoded_size to zero. This makes it simpler to just
1948 return from the function in case of failure. Free'ing up of
1949 encoder->sfe_data is the responsibility of the caller. */
1950 *encoded_size = 0;
1951
1952 if (encoder == NULL || encoded_size == NULL || errp == NULL)
1953 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1954
1955 ehp = sframe_encoder_get_header (encoder);
1956 hdrsize = sframe_get_hdr_size (ehp);
1957 fsz = sframe_encoder_get_num_fidx (encoder)
1958 * sizeof (sframe_func_desc_entry);
1959 fresz = encoder->sfe_fre_nbytes;
1960
1961 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1962 Entries section and the FRE section. */
1963 bufsize = hdrsize + fsz + fresz;
1964 encoder->sfe_data = (char *) malloc (bufsize);
1965 if (encoder->sfe_data == NULL)
1966 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1967 encoder->sfe_data_size = bufsize;
1968
1969 /* Update the information in the SFrame header. */
1970 /* SFrame FDE section follows immediately after the header. */
1971 ehp->sfh_fdeoff = 0;
1972 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1973 ehp->sfh_freoff = fsz;
1974 ehp->sfh_fre_len = fresz;
1975
1976 foreign_endian = need_swapping (ehp->sfh_abi_arch);
1977
1978 /* Write out the FDE Index and the FRE table in the sfe_data. */
1979 if (sframe_encoder_write_sframe (encoder))
1980 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1981
1982 /* Endian flip the contents if necessary. */
1983 if (foreign_endian)
1984 {
1985 if (flip_sframe (encoder->sfe_data, bufsize, 1))
1986 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1987 flip_header ((sframe_header*)encoder->sfe_data);
1988 }
1989
1990 *encoded_size = bufsize;
1991 return encoder->sfe_data;
1992}