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