]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - libsframe/sframe.c
libsframe: use appropriate data types for args of sframe_encode
[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
3412dcec
IB
1251 and ABI information. Uses the ABI specific FIXED_FP_OFFSET and
1252 FIXED_RA_OFFSET values as provided. Sets errp if failure. */
19e559f1
WP
1253
1254sframe_encoder_ctx *
3412dcec 1255sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch,
19e559f1
WP
1256 int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp)
1257{
1258 sframe_header *hp;
cb45766e 1259 sframe_encoder_ctx *encoder;
19e559f1
WP
1260
1261 if (ver != SFRAME_VERSION)
1262 return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL);
1263
cb45766e 1264 if ((encoder = malloc (sizeof (sframe_encoder_ctx))) == NULL)
19e559f1
WP
1265 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1266
cb45766e 1267 memset (encoder, 0, sizeof (sframe_encoder_ctx));
19e559f1
WP
1268
1269 /* Get the SFrame header and update it. */
cb45766e 1270 hp = sframe_encoder_get_header (encoder);
19e559f1
WP
1271 hp->sfh_preamble.sfp_version = ver;
1272 hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
1273 hp->sfh_preamble.sfp_flags = flags;
1274
1275 hp->sfh_abi_arch = abi_arch;
1276 hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset;
1277 hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset;
1278
cb45766e 1279 return encoder;
19e559f1
WP
1280}
1281
1282/* Free the encoder context. */
1283
1284void
cf0e0a0b 1285sframe_encoder_free (sframe_encoder_ctx **encoder)
19e559f1
WP
1286{
1287 if (encoder != NULL)
1288 {
cf0e0a0b
IB
1289 sframe_encoder_ctx *ectx = *encoder;
1290 if (ectx == NULL)
1291 return;
1292
1293 if (ectx->sfe_funcdesc != NULL)
1294 {
1295 free (ectx->sfe_funcdesc);
1296 ectx->sfe_funcdesc = NULL;
1297 }
1298 if (ectx->sfe_fres != NULL)
1299 {
1300 free (ectx->sfe_fres);
1301 ectx->sfe_fres = NULL;
1302 }
1303 if (ectx->sfe_data != NULL)
1304 {
1305 free (ectx->sfe_data);
1306 ectx->sfe_data = NULL;
1307 }
1308
1309 free (*encoder);
1310 *encoder = NULL;
19e559f1
WP
1311 }
1312}
1313
1314/* Get the size of the SFrame header from the encoder ctx ENCODER. */
1315
1316unsigned int
1317sframe_encoder_get_hdr_size (sframe_encoder_ctx *encoder)
1318{
1319 sframe_header *ehp;
1320 ehp = sframe_encoder_get_header (encoder);
1321 return sframe_get_hdr_size (ehp);
1322}
1323
1324/* Get the abi/arch info from the SFrame encoder context ENCODER. */
1325
de4879fe 1326uint8_t
19e559f1
WP
1327sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
1328{
de4879fe 1329 uint8_t abi_arch = 0;
19e559f1
WP
1330 sframe_header *ehp;
1331 ehp = sframe_encoder_get_header (encoder);
1332 if (ehp)
1333 abi_arch = ehp->sfh_abi_arch;
1334 return abi_arch;
1335}
1336
1337/* Return the number of function descriptor entries in the SFrame encoder
1338 ENCODER. */
1339
1340unsigned int
1341sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
1342{
1343 unsigned int num_fdes = 0;
1344 sframe_header *ehp = NULL;
1345 ehp = sframe_encoder_get_header (encoder);
1346 if (ehp)
1347 num_fdes = ehp->sfh_num_fdes;
1348 return num_fdes;
1349}
1350
1351/* Add an FRE to function at FUNC_IDX'th function descriptor entry in
1352 the encoder context. */
1353
1354int
1355sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
1e2a61ef
IB
1356 unsigned int func_idx,
1357 sframe_frame_row_entry *frep)
19e559f1
WP
1358{
1359 sframe_header *ehp;
1360 sframe_func_desc_entry *fdep;
1361 sframe_frame_row_entry *ectx_frep;
1362 size_t offsets_sz, esz;
100d405d 1363 uint32_t fre_type;
19e559f1
WP
1364 size_t fre_tbl_sz;
1365 int err = 0;
1366
1367 if (encoder == NULL || frep == NULL)
1368 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1369 if (!sframe_fre_sanity_check_p (frep))
1370 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1371
1372 /* Use func_idx to gather the function descriptor entry. */
1373 fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
1374
1375 if (fdep == NULL)
1376 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND);
1377
1378 fre_type = sframe_get_fre_type (fdep);
1466e49f 1379 sf_fre_tbl *fre_tbl = encoder->sfe_fres;
19e559f1
WP
1380
1381 if (fre_tbl == NULL)
1382 {
1383 fre_tbl_sz = (sizeof (sf_fre_tbl)
1384 + (number_of_entries * sizeof (sframe_frame_row_entry)));
1385 fre_tbl = malloc (fre_tbl_sz);
1386
1387 if (fre_tbl == NULL)
1388 {
1389 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1390 goto bad; /* OOM. */
1391 }
1392 memset (fre_tbl, 0, fre_tbl_sz);
1393 fre_tbl->alloced = number_of_entries;
1394 }
1395 else if (fre_tbl->count == fre_tbl->alloced)
1396 {
1397 fre_tbl_sz = (sizeof (sf_fre_tbl)
1398 + ((fre_tbl->alloced + number_of_entries)
1399 * sizeof (sframe_frame_row_entry)));
1400 fre_tbl = realloc (fre_tbl, fre_tbl_sz);
1401 if (fre_tbl == NULL)
1402 {
1403 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1404 goto bad; /* OOM. */
1405 }
1406
1407 memset (&fre_tbl->entry[fre_tbl->alloced], 0,
1408 number_of_entries * sizeof (sframe_frame_row_entry));
1409 fre_tbl->alloced += number_of_entries;
1410 }
1411
1412 ectx_frep = &fre_tbl->entry[fre_tbl->count];
1413 ectx_frep->fre_start_addr
1414 = frep->fre_start_addr;
1415 ectx_frep->fre_info = frep->fre_info;
1416
1417 if (fdep->sfde_func_size)
1418 sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
1419 else
1420 /* A SFrame FDE with func size equal to zero is possible. */
1421 sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
1422
1423 /* frep has already been sanity check'd. Get offsets size. */
1424 offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1425 memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
1426
1427 esz = sframe_fre_entry_size (frep, fre_type);
1428 fre_tbl->count++;
1429
1466e49f 1430 encoder->sfe_fres = fre_tbl;
19e559f1
WP
1431 encoder->sfe_fre_nbytes += esz;
1432
1433 ehp = sframe_encoder_get_header (encoder);
1434 ehp->sfh_num_fres = fre_tbl->count;
1435
1436 /* Update the value of the number of FREs for the function. */
1437 fdep->sfde_func_num_fres++;
1438
1439 return 0;
1440
1441bad:
1442 if (fre_tbl != NULL)
1443 free (fre_tbl);
1444 encoder->sfe_fres = NULL;
1445 encoder->sfe_fre_nbytes = 0;
1446 return -1;
1447}
1448
1449/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
1450 to the encoder. */
1451
1452int
1453sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
1e2a61ef
IB
1454 int32_t start_addr,
1455 uint32_t func_size,
1456 unsigned char func_info,
1457 uint32_t num_fres __attribute__ ((unused)))
19e559f1
WP
1458{
1459 sframe_header *ehp;
1466e49f 1460 sf_fde_tbl *fd_info;
19e559f1
WP
1461 size_t fd_tbl_sz;
1462 int err = 0;
1463
1464 /* FIXME book-keep num_fres for error checking. */
1465 if (encoder == NULL)
1466 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1467
1466e49f 1468 fd_info = encoder->sfe_funcdesc;
19e559f1
WP
1469 ehp = sframe_encoder_get_header (encoder);
1470
1471 if (fd_info == NULL)
1472 {
1466e49f 1473 fd_tbl_sz = (sizeof (sf_fde_tbl)
19e559f1
WP
1474 + (number_of_entries * sizeof (sframe_func_desc_entry)));
1475 fd_info = malloc (fd_tbl_sz);
1476 if (fd_info == NULL)
1477 {
1478 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1479 goto bad; /* OOM. */
1480 }
1481 memset (fd_info, 0, fd_tbl_sz);
1482 fd_info->alloced = number_of_entries;
1483 }
1484 else if (fd_info->count == fd_info->alloced)
1485 {
1466e49f 1486 fd_tbl_sz = (sizeof (sf_fde_tbl)
19e559f1
WP
1487 + ((fd_info->alloced + number_of_entries)
1488 * sizeof (sframe_func_desc_entry)));
1489 fd_info = realloc (fd_info, fd_tbl_sz);
1490 if (fd_info == NULL)
1491 {
1492 sframe_set_errno (&err, SFRAME_ERR_NOMEM);
1493 goto bad; /* OOM. */
1494 }
1495
1496 memset (&fd_info->entry[fd_info->alloced], 0,
1497 number_of_entries * sizeof (sframe_func_desc_entry));
1498 fd_info->alloced += number_of_entries;
1499 }
1500
1501 fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
1502 /* Num FREs is updated as FREs are added for the function later via
1503 sframe_encoder_add_fre. */
1504 fd_info->entry[fd_info->count].sfde_func_size = func_size;
1505 fd_info->entry[fd_info->count].sfde_func_start_fre_off
1506 = encoder->sfe_fre_nbytes;
1507#if 0
1508 // Linker optimization test code cleanup later ibhagat TODO FIXME
100d405d 1509 uint32_t fre_type = sframe_calc_fre_type (func_size);
19e559f1
WP
1510
1511 fd_info->entry[fd_info->count].sfde_func_info
1512 = sframe_fde_func_info (fre_type);
1513#endif
1514 fd_info->entry[fd_info->count].sfde_func_info = func_info;
1515 fd_info->count++;
1466e49f 1516 encoder->sfe_funcdesc = fd_info;
19e559f1
WP
1517 ehp->sfh_num_fdes++;
1518 return 0;
1519
1520bad:
1521 if (fd_info != NULL)
1522 free (fd_info);
1523 encoder->sfe_funcdesc = NULL;
1524 ehp->sfh_num_fdes = 0;
1525 return -1;
1526}
1527
1528static int
1529sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
1530{
1531 sframe_header *ehp;
1532
1533 ehp = sframe_encoder_get_header (encoder);
1534 /* Sort and write out the FDE table. */
1466e49f 1535 sf_fde_tbl *fd_info = encoder->sfe_funcdesc;
19e559f1
WP
1536 if (fd_info)
1537 {
1538 qsort (fd_info->entry, fd_info->count,
1539 sizeof (sframe_func_desc_entry), fde_func);
1540 /* Update preamble's flags. */
1541 ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
1542 }
1543 return 0;
1544}
1545
68bb0d27
IB
1546/* Write the SFrame FRE start address from the in-memory FRE_START_ADDR
1547 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and
1548 FRE_START_ADDR_SZ. */
1549
1550static int
1551sframe_encoder_write_fre_start_addr (char *contents,
1552 uint32_t fre_start_addr,
100d405d 1553 uint32_t fre_type,
68bb0d27
IB
1554 size_t fre_start_addr_sz)
1555{
1556 int err = 0;
1557
1558 if (fre_type == SFRAME_FRE_TYPE_ADDR1)
1559 {
1560 uint8_t uc = fre_start_addr;
1561 memcpy (contents, &uc, fre_start_addr_sz);
1562 }
1563 else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
1564 {
1565 uint16_t ust = fre_start_addr;
1566 memcpy (contents, &ust, fre_start_addr_sz);
1567 }
1568 else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
1569 {
1570 uint32_t uit = fre_start_addr;
1571 memcpy (contents, &uit, fre_start_addr_sz);
1572 }
1573 else
1574 return sframe_set_errno (&err, SFRAME_ERR_INVAL);
1575
1576 return 0;
1577}
1578
19e559f1
WP
1579/* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The
1580 size in bytes written out are updated in ESZ.
1581
1582 This function works closely with the SFrame binary format.
1583
1584 Returns SFRAME_ERR if failure. */
1585
1586static int
1587sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
100d405d 1588 uint32_t fre_type, size_t *esz)
19e559f1 1589{
3cae2580 1590 size_t fre_sz;
19e559f1
WP
1591 size_t fre_start_addr_sz;
1592 size_t fre_stack_offsets_sz;
1593 int err = 0;
1594
1595 if (!sframe_fre_sanity_check_p (frep))
1596 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1597
1598 fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
1599 fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
1600
1601 /* The FRE start address must be encodable in the available number of
1602 bytes. */
1603 uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
1604 sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
1605
68bb0d27
IB
1606 sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr,
1607 fre_type, fre_start_addr_sz);
19e559f1
WP
1608 contents += fre_start_addr_sz;
1609
3cae2580 1610 memcpy (contents, &frep->fre_info, sizeof (frep->fre_info));
19e559f1
WP
1611 contents += sizeof (frep->fre_info);
1612
3cae2580 1613 memcpy (contents, frep->fre_offsets, fre_stack_offsets_sz);
19e559f1
WP
1614 contents+= fre_stack_offsets_sz;
1615
3cae2580 1616 fre_sz = sframe_fre_entry_size (frep, fre_type);
19e559f1
WP
1617 /* Sanity checking. */
1618 sframe_assert ((fre_start_addr_sz
3cae2580
IB
1619 + sizeof (frep->fre_info)
1620 + fre_stack_offsets_sz) == fre_sz);
19e559f1 1621
3cae2580 1622 *esz = fre_sz;
19e559f1
WP
1623
1624 return 0;
1625}
1626
1627/* Serialize the core contents of the SFrame section and write out to the
1628 output buffer held in the ENCODER. Return SFRAME_ERR if failure. */
1629
1630static int
1631sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
1632{
1633 char *contents;
1634 size_t buf_size;
1635 size_t hdr_size;
1636 size_t all_fdes_size;
1637 size_t fre_size;
1638 size_t esz = 0;
1639 sframe_header *ehp;
1640 unsigned char flags;
1466e49f 1641 sf_fde_tbl *fd_info;
19e559f1
WP
1642 sf_fre_tbl *fr_info;
1643 uint32_t i, num_fdes;
1644 uint32_t j, num_fres;
1645 sframe_func_desc_entry *fdep;
1646 sframe_frame_row_entry *frep;
1647
100d405d 1648 uint32_t fre_type;
19e559f1
WP
1649 int err = 0;
1650
1651 contents = encoder->sfe_data;
1652 buf_size = encoder->sfe_data_size;
1653 num_fdes = sframe_encoder_get_num_fidx (encoder);
1654 all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
1655 ehp = sframe_encoder_get_header (encoder);
1656 hdr_size = sframe_get_hdr_size (ehp);
1657
1466e49f
IB
1658 fd_info = encoder->sfe_funcdesc;
1659 fr_info = encoder->sfe_fres;
19e559f1
WP
1660
1661 /* Sanity checks:
1662 - buffers must be malloc'd by the caller. */
1663 if ((contents == NULL) || (buf_size < hdr_size))
1664 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL);
1665 if (fr_info == NULL)
1666 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
1667
1668 /* Write out the FRE table first.
1669
1670 Recall that read/write of FREs needs information from the corresponding
1671 FDE; the latter stores the information about the FRE type record used for
1672 the function. Also note that sorting of FDEs does NOT impact the order
1673 in which FREs are stored in the SFrame's FRE sub-section. This means
1674 that writing out FREs after sorting of FDEs will need some additional
1675 book-keeping. At this time, we can afford to avoid it by writing out
1676 the FREs first to the output buffer. */
1677 fre_size = 0;
1678 uint32_t global = 0;
1679 uint32_t fre_index = 0;
1680
1681 contents += hdr_size + all_fdes_size;
1682 for (i = 0; i < num_fdes; i++)
1683 {
1684 fdep = &fd_info->entry[i];
1685 fre_type = sframe_get_fre_type (fdep);
1686 num_fres = fdep->sfde_func_num_fres;
1687
1688 for (j = 0; j < num_fres; j++)
1689 {
1690 fre_index = global + j;
1691 frep = &fr_info->entry[fre_index];
1692
1693 sframe_encoder_write_fre (contents, frep, fre_type, &esz);
1694 contents += esz;
1695 fre_size += esz; /* For debugging only. */
1696 }
1697 global += j;
1698 }
1699
1700 sframe_assert (fre_size == ehp->sfh_fre_len);
1701 sframe_assert (global == ehp->sfh_num_fres);
1702 sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
1703
1704 /* Sort the FDE table */
1705 sframe_sort_funcdesc (encoder);
1706
1707 /* Sanity checks:
1708 - the FDE section must have been sorted by now on the start address
1709 of each function. */
1710 flags = ehp->sfh_preamble.sfp_flags;
1711 if (!(flags & SFRAME_F_FDE_SORTED)
1712 || (fd_info == NULL))
1713 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL);
1714
1715 contents = encoder->sfe_data;
1716 /* Write out the SFrame header. The SFrame header in the encoder
1717 object has already been updated with correct offsets by the caller. */
1718 memcpy (contents, ehp, hdr_size);
1719 contents += hdr_size;
1720
1721 /* Write out the FDE table sorted on funtion start address. */
1722 memcpy (contents, fd_info->entry, all_fdes_size);
1723 contents += all_fdes_size;
1724
1725 return 0;
1726}
1727
1728/* Serialize the contents of the encoder and return the buffer. ENCODED_SIZE
1729 is updated to the size of the buffer. */
1730
1731char *
1732sframe_encoder_write (sframe_encoder_ctx *encoder,
1733 size_t *encoded_size, int *errp)
1734{
1735 sframe_header *ehp;
1736 size_t hdrsize, fsz, fresz, bufsize;
1737 int foreign_endian;
1738
1739 /* Initialize the encoded_size to zero. This makes it simpler to just
1740 return from the function in case of failure. Free'ing up of
1741 encoder->sfe_data is the responsibility of the caller. */
1742 *encoded_size = 0;
1743
1744 if (encoder == NULL || encoded_size == NULL || errp == NULL)
1745 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL);
1746
1747 ehp = sframe_encoder_get_header (encoder);
1748 hdrsize = sframe_get_hdr_size (ehp);
1749 fsz = sframe_encoder_get_num_fidx (encoder)
1750 * sizeof (sframe_func_desc_entry);
1751 fresz = encoder->sfe_fre_nbytes;
1752
1753 /* The total size of buffer is the sum of header, SFrame Function Descriptor
1754 Entries section and the FRE section. */
1755 bufsize = hdrsize + fsz + fresz;
1756 encoder->sfe_data = (char *) malloc (bufsize);
1757 if (encoder->sfe_data == NULL)
1758 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM);
1759 encoder->sfe_data_size = bufsize;
1760
1761 /* Update the information in the SFrame header. */
1762 /* SFrame FDE section follows immediately after the header. */
1763 ehp->sfh_fdeoff = 0;
1764 /* SFrame FRE section follows immediately after the SFrame FDE section. */
1765 ehp->sfh_freoff = fsz;
1766 ehp->sfh_fre_len = fresz;
1767
1768 foreign_endian = need_swapping (ehp->sfh_abi_arch);
1769
1770 /* Write out the FDE Index and the FRE table in the sfe_data. */
1771 if (sframe_encoder_write_sframe (encoder))
1772 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1773
1774 /* Endian flip the contents if necessary. */
1775 if (foreign_endian)
1776 {
1777 if (flip_sframe (encoder->sfe_data, bufsize, 1))
1778 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL);
1779 flip_header ((sframe_header*)encoder->sfe_data);
1780 }
1781
1782 *encoded_size = bufsize;
1783 return encoder->sfe_data;
1784}