1 /* sframe.c - SFrame decoder/encoder. 2 3 Copyright (C) 2022-2024 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 } 1899