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