]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - libsframe/sframe.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / libsframe / sframe.c
CommitLineData
19e559f1
WP
1/* sframe.c - SFrame decoder/encoder.
2
e8e7cf2a 3 Copyright (C) 2022-2025 Free Software Foundation, Inc.
19e559f1
WP
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>
72dac980 25#include <stddef.h>
19e559f1
WP
26#include "sframe-impl.h"
27#include "swap.h"
28
1466e49f 29struct sf_fde_tbl
19e559f1
WP
30{
31 unsigned int count;
32 unsigned int alloced;
33 sframe_func_desc_entry entry[1];
1466e49f 34};
19e559f1 35
1466e49f 36struct sf_fre_tbl
19e559f1
WP
37{
38 unsigned int count;
39 unsigned int alloced;
40 sframe_frame_row_entry entry[1];
1466e49f 41};
19e559f1
WP
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
e80578be
IB
116static uint8_t
117sframe_fre_get_offset_count (uint8_t fre_info)
19e559f1
WP
118{
119 return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
120}
121
e80578be
IB
122static uint8_t
123sframe_fre_get_offset_size (uint8_t fre_info)
19e559f1
WP
124{
125 return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
126}
127
9c4b163c 128static bool
e80578be 129sframe_get_fre_ra_mangled_p (uint8_t fre_info)
9c4b163c
IB
130{
131 return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
132}
133
19e559f1
WP
134/* Access functions for info from function descriptor entry. */
135
100d405d 136static uint32_t
19e559f1
WP
137sframe_get_fre_type (sframe_func_desc_entry *fdep)
138{
100d405d 139 uint32_t fre_type = 0;
19e559f1
WP
140 if (fdep)
141 fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
142 return fre_type;
143}
144
100d405d 145static uint32_t
19e559f1
WP
146sframe_get_fde_type (sframe_func_desc_entry *fdep)
147{
100d405d 148 uint32_t fde_type = 0;
19e559f1
WP
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
26be6015 205static bool
19e559f1
WP
206sframe_header_sanity_check_p (sframe_header *hp)
207{
19e559f1 208 /* Check preamble is valid. */
ce9a8725
IB
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)
dcb0cf7b 212 || (hp->sfh_preamble.sfp_flags & ~SFRAME_V2_F_ALL_FLAGS))
26be6015 213 return false;
19e559f1
WP
214
215 /* Check offsets are valid. */
216 if (hp->sfh_fdeoff > hp->sfh_freoff)
26be6015 217 return false;
19e559f1 218
26be6015 219 return true;
19e559f1
WP
220}
221
222/* Flip the start address pointed to by FP. */
223
224static void
100d405d 225flip_fre_start_address (char *addr, uint32_t fre_type)
19e559f1 226{
19e559f1
WP
227 if (fre_type == SFRAME_FRE_TYPE_ADDR2)
228 {
a5ffdcaf 229 uint16_t *start_addr = (uint16_t *)addr;
19e559f1
WP
230 swap_thing (*start_addr);
231 }
232 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
233 {
a5ffdcaf 234 uint32_t *start_addr = (uint32_t *)addr;
19e559f1
WP
235 swap_thing (*start_addr);
236 }
237}
238
239static void
a5ffdcaf 240flip_fre_stack_offsets (char *offsets, uint8_t offset_size, uint8_t offset_cnt)
19e559f1
WP
241{
242 int j;
19e559f1
WP
243
244 if (offset_size == SFRAME_FRE_OFFSET_2B)
245 {
a5ffdcaf 246 uint16_t *ust = (uint16_t *)offsets;
19e559f1
WP
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
100d405d 261sframe_fre_start_addr_size (uint32_t fre_type)
19e559f1
WP
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
26be6015 285static bool
19e559f1
WP
286sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
287{
e80578be
IB
288 uint8_t offset_size, offset_cnt;
289 uint8_t fre_info;
19e559f1
WP
290
291 if (frep == NULL)
26be6015 292 return false;
19e559f1
WP
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)
26be6015 300 return false;
19e559f1
WP
301
302 offset_cnt = sframe_fre_get_offset_count (fre_info);
d987df5c 303 if (offset_cnt > MAX_NUM_STACK_OFFSETS)
26be6015 304 return false;
19e559f1 305
26be6015 306 return true;
19e559f1
WP
307}
308
309/* Get FRE_INFO's offset size in bytes. */
310
311static size_t
e80578be 312sframe_fre_offset_bytes_size (uint8_t fre_info)
19e559f1 313{
e80578be 314 uint8_t offset_size, offset_cnt;
19e559f1
WP
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
100d405d 333sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
19e559f1
WP
334{
335 if (frep == NULL)
336 return 0;
337
e80578be 338 uint8_t fre_info = frep->fre_info;
19e559f1
WP
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
676cb9d2
IB
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;
df6f1afb 353 uint32_t num_fdes;
676cb9d2
IB
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
0b1bf2fc
IB
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
3169b734
IB
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
0b1bf2fc 394sframe_fre_check_range_p (sframe_decoder_ctx *dctx, uint32_t func_idx,
2adbf167 395 uint32_t start_ip_offset, uint32_t end_ip_offset,
3169b734
IB
396 int32_t pc)
397{
0b1bf2fc 398 sframe_func_desc_entry *fdep;
3169b734 399 int32_t func_start_addr;
ce9a8725 400 uint8_t rep_block_size;
3169b734 401 uint32_t fde_type;
2adbf167 402 uint32_t pc_offset;
3169b734 403 bool mask_p;
3169b734 404
0b1bf2fc
IB
405 fdep = &dctx->sfd_funcdesc[func_idx];
406 func_start_addr = sframe_decoder_get_secrel_func_start_addr (dctx, func_idx);
3169b734
IB
407 fde_type = sframe_get_fde_type (fdep);
408 mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
ce9a8725 409 rep_block_size = fdep->sfde_func_rep_size;
3169b734 410
2adbf167
JR
411 if (func_start_addr > pc)
412 return false;
413
414 /* Given func_start_addr <= pc, pc - func_start_addr must be positive. */
4e94f007
IB
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;
3169b734 420
4e94f007 421 return (start_ip_offset <= pc_offset) && (end_ip_offset >= pc_offset);
3169b734
IB
422}
423
19e559f1 424static int
100d405d 425flip_fre (char *fp, uint32_t fre_type, size_t *fre_size)
19e559f1 426{
e80578be
IB
427 uint8_t fre_info;
428 uint8_t offset_size, offset_cnt;
19e559f1
WP
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
e80578be
IB
441 /* FRE info is uint8_t. No need to flip. */
442 fre_info = *(uint8_t*)fp;
19e559f1
WP
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. */
e80578be 447 fre_info_size = sizeof (uint8_t);
19e559f1
WP
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;
100d405d 478 uint32_t fre_type = 0;
19e559f1
WP
479 uint32_t fre_offset = 0;
480 size_t esz = 0;
cd9aea32 481 size_t hdrsz = 0;
19e559f1 482 int err = 0;
cd9aea32
IB
483 /* For error checking. */
484 size_t bytes_flipped = 0;
19e559f1
WP
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. */
cd9aea32 494 hdrsz = sframe_get_hdr_size (ihp);
19e559f1 495 num_fdes = ihp->sfh_num_fdes;
cd9aea32 496 fdes = frame_buf + hdrsz + ihp->sfh_fdeoff;
19e559f1
WP
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 {
cd9aea32
IB
503 if ((char*)fdep >= (frame_buf + buf_size))
504 goto bad;
505
19e559f1
WP
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);
cd9aea32 514 bytes_flipped += sizeof (sframe_func_desc_entry);
19e559f1
WP
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;
cd9aea32 529 bytes_flipped += esz;
19e559f1 530
cd9aea32 531 if (esz == 0 || esz > buf_size)
19e559f1
WP
532 goto bad;
533 fp += esz;
534 }
535 prev_frep_index = j;
536 }
cd9aea32
IB
537 /* All FDEs and FREs must have been endian flipped by now. */
538 if ((j != ihp->sfh_num_fres) || (bytes_flipped != (buf_size - hdrsz)))
19e559f1
WP
539 goto bad;
540
541 /* Success. */
542 return 0;
543bad:
544 return SFRAME_ERR;
545}
546
547/* The SFrame Decoder. */
548
cb45766e 549/* Get SFrame header from the given decoder context DCTX. */
19e559f1
WP
550
551static sframe_header *
cb45766e 552sframe_decoder_get_header (sframe_decoder_ctx *dctx)
19e559f1
WP
553{
554 sframe_header *hp = NULL;
cb45766e
IB
555 if (dctx != NULL)
556 hp = &dctx->sfd_header;
19e559f1
WP
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{
e80578be 580 uint8_t offset_cnt, offset_size;
19e559f1
WP
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
cb45766e 614sframe_decoder_free (sframe_decoder_ctx **dctxp)
19e559f1 615{
cb45766e 616 if (dctxp != NULL)
19e559f1 617 {
cb45766e 618 sframe_decoder_ctx *dctx = *dctxp;
19e559f1
WP
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 }
995bc597
IB
632 if (dctx->sfd_buf != NULL)
633 {
634 free (dctx->sfd_buf);
635 dctx->sfd_buf = NULL;
636 }
19e559f1 637
cb45766e
IB
638 free (*dctxp);
639 *dctxp = NULL;
19e559f1
WP
640 }
641}
642
b659fb35 643/* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE. */
19e559f1
WP
644/* FIXME API for linker. Revisit if its better placed somewhere else? */
645
646unsigned char
100d405d
IB
647sframe_fde_create_func_info (uint32_t fre_type,
648 uint32_t fde_type)
19e559f1
WP
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
49e4485c 663uint32_t
725a19bf 664sframe_calc_fre_type (size_t func_size)
19e559f1 665{
100d405d 666 uint32_t fre_type = 0;
3f107464 667 if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT)
19e559f1 668 fre_type = SFRAME_FRE_TYPE_ADDR1;
3f107464 669 else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT)
19e559f1 670 fre_type = SFRAME_FRE_TYPE_ADDR2;
725a19bf
IB
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))
19e559f1
WP
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
a9f1da26 680uint8_t
19e559f1
WP
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
e80578be 686 uint8_t fre_info = fre->fre_info;
19e559f1
WP
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;
526960c9
IB
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 }
19e559f1
WP
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. */
526960c9
IB
719 fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
720 != SFRAME_CFA_FIXED_RA_INVALID)
19e559f1
WP
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{
36aecb41
IB
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 }
19e559f1
WP
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
9c4b163c
IB
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
19e559f1 758static int
f4af4272
IB
759sframe_frame_row_entry_copy (sframe_frame_row_entry *dst,
760 sframe_frame_row_entry *src)
19e559f1
WP
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
8c078abd
IB
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
19e559f1
WP
776static int
777sframe_decode_fre_start_address (const char *fre_buf,
778 uint32_t *fre_start_addr,
100d405d 779 uint32_t fre_type)
19e559f1
WP
780{
781 uint32_t saddr = 0;
782 int err = 0;
8c078abd
IB
783 size_t addr_size = 0;
784
785 addr_size = sframe_fre_start_addr_size (fre_type);
19e559f1
WP
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;
8c078abd
IB
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;
19e559f1
WP
800 }
801 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
802 {
803 uint32_t *uit = (uint32_t *)fre_buf;
f4af4272 804 uint32_t tmp = 0;
8c078abd
IB
805 memcpy (&tmp, uit, addr_size);
806 saddr = (uint32_t)tmp;
19e559f1
WP
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,
100d405d 824 uint32_t fre_type, size_t *esz)
19e559f1
WP
825{
826 int err = 0;
812d8688 827 const char *stack_offsets = NULL;
19e559f1
WP
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);
e80578be 839 fre->fre_info = *(uint8_t *)(fre_buf + addr_size);
19e559f1 840 /* Sanity check as the API works closely with the binary format. */
e80578be 841 sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t));
19e559f1
WP
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);
812d8688 848 stack_offsets = fre_buf + addr_size + sizeof (fre->fre_info);
19e559f1
WP
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)
1e2a61ef 854 + stack_offsets_sz));
19e559f1
WP
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;
995bc597
IB
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;
19e559f1
WP
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 {
87f5e2ed 938 sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
19e559f1
WP
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. */
1466e49f 960 dctx->sfd_fres = (char *) malloc (sfheaderp->sfh_fre_len);
19e559f1
WP
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
de4879fe 993/* Get the SFrame's abi/arch info given the decoder context DCTX. */
19e559f1 994
de4879fe
IB
995uint8_t
996sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx)
19e559f1
WP
997{
998 sframe_header *sframe_header;
de4879fe 999 sframe_header = sframe_decoder_get_header (dctx);
19e559f1
WP
1000 return sframe_header->sfh_abi_arch;
1001}
1002
9f71b60b
IB
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
251c6789
IB
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
19e559f1
WP
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
72dac980
IB
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
852bb8c1
IB
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
19e559f1
WP
1075/* Find the function descriptor entry starting which contains the specified
1076 address ADDR. */
1077
852bb8c1
IB
1078static sframe_func_desc_entry *
1079sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr,
0b1bf2fc 1080 int *errp, uint32_t *func_idx)
19e559f1
WP
1081{
1082 sframe_header *dhp;
1083 sframe_func_desc_entry *fdp;
9d2a2434 1084 int low, high;
19e559f1
WP
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. */
251c6789 1095 if ((sframe_decoder_get_flags (ctx) & SFRAME_F_FDE_SORTED) == 0)
19e559f1
WP
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;
d984b08b 1101 high = dhp->sfh_num_fdes - 1;
19e559f1
WP
1102 while (low <= high)
1103 {
1104 int mid = low + (high - low) / 2;
1105
9d2a2434
JR
1106 /* Given sfde_func_start_address <= addr,
1107 addr - sfde_func_start_address must be positive. */
0b1bf2fc
IB
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))
9d2a2434 1111 < fdp[mid].sfde_func_size))
0b1bf2fc
IB
1112 {
1113 *func_idx = mid;
1114 return fdp + mid;
1115 }
19e559f1 1116
0b1bf2fc 1117 if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) < addr)
9d2a2434 1118 low = mid + 1;
19e559f1
WP
1119 else
1120 high = mid - 1;
1121 }
1122
1123 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND);
1124}
1125
83c21987
IB
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
19e559f1
WP
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{
83c21987 1159 sframe_frame_row_entry cur_fre;
19e559f1 1160 sframe_func_desc_entry *fdep;
0b1bf2fc 1161 uint32_t func_idx;
ada5c6fa 1162 uint32_t fre_type, i;
83c21987 1163 int32_t func_start_addr;
2adbf167 1164 uint32_t start_ip_offset, end_ip_offset;
83c21987 1165 const char *fres;
19e559f1 1166 size_t size = 0;
83c21987 1167 int err = 0;
19e559f1
WP
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. */
0b1bf2fc 1173 fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err, &func_idx);
19e559f1
WP
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);
19e559f1 1178
812d8688 1179 fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
0b1bf2fc 1180 func_start_addr = sframe_decoder_get_secrel_func_start_addr (ctx, func_idx);
83c21987 1181
19e559f1
WP
1182 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1183 {
83c21987
IB
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
3169b734 1188 start_ip_offset = cur_fre.fre_start_addr;
83c21987 1189 end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
19e559f1 1190
2adbf167
JR
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))
83c21987
IB
1194 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1195
0b1bf2fc
IB
1196 if (sframe_fre_check_range_p (ctx, func_idx, start_ip_offset,
1197 end_ip_offset, pc))
19e559f1 1198 {
83c21987
IB
1199 sframe_frame_row_entry_copy (frep, &cur_fre);
1200 return 0;
19e559f1 1201 }
83c21987 1202 fres += size;
19e559f1
WP
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
df6f1afb 1210uint32_t
19e559f1
WP
1211sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
1212{
df6f1afb 1213 uint32_t num_fdes = 0;
19e559f1
WP
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;
19e559f1
WP
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
676cb9d2
IB
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);
19e559f1 1246
19e559f1
WP
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
ce9a8725
IB
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}
19e559f1
WP
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,
1e2a61ef
IB
1291 unsigned int func_idx,
1292 unsigned int fre_idx,
1293 sframe_frame_row_entry *fre)
19e559f1
WP
1294{
1295 sframe_func_desc_entry *fdep;
1296 sframe_frame_row_entry ifre;
812d8688 1297 const char *fres;
19e559f1 1298 uint32_t i;
100d405d 1299 uint32_t fre_type;
19e559f1
WP
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. */
812d8688 1314 fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
19e559f1
WP
1315 for (i = 0; i < fdep->sfde_func_num_fres; i++)
1316 {
1317 /* Decode the FRE at the current position. Return it if valid. */
812d8688 1318 err = sframe_decode_fre (fres, &ifre, fre_type, &esz);
19e559f1
WP
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. */
812d8688 1335 fres += esz;
19e559f1
WP
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,
1e2a61ef 1357 uint32_t func_idx)
19e559f1
WP
1358{
1359 sframe_func_desc_entry *fde = NULL;
1360 if (func_idx < sframe_encoder_get_num_fidx (encoder))
1361 {
1466e49f 1362 sf_fde_tbl *func_tbl = encoder->sfe_funcdesc;
19e559f1
WP
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
3412dcec
IB
1369 and ABI information. Uses the ABI specific FIXED_FP_OFFSET and
1370 FIXED_RA_OFFSET values as provided. Sets errp if failure. */
19e559f1
WP
1371
1372sframe_encoder_ctx *
3412dcec 1373sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
19e559f1
WP
1374 int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
1375{
1376 sframe_header *hp;
cb45766e 1377 sframe_encoder_ctx *encoder;
19e559f1
WP
1378
1379 if (ver != SFRAME_VERSION)
1380 return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
1381
cb45766e 1382 if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
19e559f1
WP
1383 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1384
cb45766e 1385 memset (encoder, 0, sizeof (sframe_encoder_ctx));
19e559f1
WP
1386
1387 /* Get the SFrame header and update it. */
cb45766e 1388 hp = sframe_encoder_get_header (encoder);
19e559f1
WP
1389 hp->sfh_preamble.sfp_version = ver;
1390 hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
1391 hp->sfh_preamble.sfp_flags = flags;
1392
0b1bf2fc
IB
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
19e559f1
WP
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
cb45766e 1403 return encoder;
19e559f1
WP
1404}
1405
1406/* Free the encoder context. */
1407
1408void
cf0e0a0b 1409sframe_encoder_free (sframe_encoder_ctx **encoder)
19e559f1
WP
1410{
1411 if (encoder != NULL)
1412 {
cf0e0a0b
IB
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;
19e559f1
WP
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
de4879fe 1450uint8_t
19e559f1
WP
1451sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
1452{
de4879fe 1453 uint8_t abi_arch = 0;
19e559f1
WP
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
9f71b60b
IB
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
251c6789
IB
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
19e559f1
WP
1480/* Return the number of function descriptor entries in the SFrame encoder
1481 ENCODER. */
1482
df6f1afb 1483uint32_t
19e559f1
WP
1484sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
1485{
df6f1afb 1486 uint32_t num_fdes = 0;
19e559f1
WP
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
72dac980
IB
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
19e559f1
WP
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,
1e2a61ef
IB
1522 unsigned int func_idx,
1523 sframe_frame_row_entry *frep)
19e559f1
WP
1524{
1525 sframe_header *ehp;
1526 sframe_func_desc_entry *fdep;
1527 sframe_frame_row_entry *ectx_frep;
1528 size_t offsets_sz, esz;
100d405d 1529 uint32_t fre_type;
19e559f1
WP
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);
1466e49f 1545 sf_fre_tbl *fre_tbl = encoder->sfe_fres;
19e559f1
WP
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
1466e49f 1596 encoder->sfe_fres = fre_tbl;
19e559f1
WP
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,
1e2a61ef
IB
1620 int32_t start_addr,
1621 uint32_t func_size,
1622 unsigned char func_info,
1623 uint32_t num_fres __attribute__ ((unused)))
19e559f1
WP
1624{
1625 sframe_header *ehp;
1466e49f 1626 sf_fde_tbl *fd_info;
19e559f1
WP
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
1466e49f 1634 fd_info = encoder->sfe_funcdesc;
19e559f1
WP
1635 ehp = sframe_encoder_get_header (encoder);
1636
1637 if (fd_info == NULL)
1638 {
1466e49f 1639 fd_tbl_sz = (sizeof (sf_fde_tbl)
19e559f1
WP
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 {
1466e49f 1652 fd_tbl_sz = (sizeof (sf_fde_tbl)
19e559f1
WP
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
100d405d 1675 uint32_t fre_type = sframe_calc_fre_type (func_size);
19e559f1
WP
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++;
1466e49f 1682 encoder->sfe_funcdesc = fd_info;
19e559f1
WP
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
ce9a8725
IB
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
19e559f1
WP
1725static int
1726sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
1727{
0b1bf2fc 1728 sframe_header *ehp = sframe_encoder_get_header (encoder);
19e559f1 1729
19e559f1 1730 /* Sort and write out the FDE table. */
1466e49f 1731 sf_fde_tbl *fd_info = encoder->sfe_funcdesc;
19e559f1
WP
1732 if (fd_info)
1733 {
0b1bf2fc
IB
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
19e559f1
WP
1743 qsort (fd_info->entry, fd_info->count,
1744 sizeof (sframe_func_desc_entry), fde_func);
0b1bf2fc
IB
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
19e559f1
WP
1750 /* Update preamble's flags. */
1751 ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
1752 }
1753 return 0;
1754}
1755
68bb0d27
IB
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,
100d405d 1763 uint32_t fre_type,
68bb0d27
IB
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
19e559f1
WP
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,
100d405d 1798 uint32_t fre_type, size_t *esz)
19e559f1 1799{
3cae2580 1800 size_t fre_sz;
19e559f1
WP
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
68bb0d27
IB
1816 sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
1817 fre_type, fre_start_addr_sz);
19e559f1
WP
1818 contents += fre_start_addr_sz;
1819
3cae2580 1820 memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
19e559f1
WP
1821 contents += sizeof (frep->fre_info);
1822
3cae2580 1823 memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
19e559f1
WP
1824 contents+= fre_stack_offsets_sz;
1825
3cae2580 1826 fre_sz = sframe_fre_entry_size (frep, fre_type);
19e559f1
WP
1827 /* Sanity checking. */
1828 sframe_assert ((fre_start_addr_sz
3cae2580
IB
1829 + sizeof (frep->fre_info)
1830 + fre_stack_offsets_sz) == fre_sz);
19e559f1 1831
3cae2580 1832 *esz = fre_sz;
19e559f1
WP
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;
1466e49f 1850 sf_fde_tbl *fd_info;
19e559f1
WP
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
100d405d 1857 uint32_t fre_type;
19e559f1
WP
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
1466e49f
IB
1867 fd_info = encoder->sfe_funcdesc;
1868 fr_info = encoder->sfe_fres;
19e559f1
WP
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. */
251c6789 1919 if (!(sframe_encoder_get_flags (encoder) & SFRAME_F_FDE_SORTED)
19e559f1
WP
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}