1 /* sframe.c - SFrame decoder/encoder. 2 3 Copyright (C) 2022-2026 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 <stddef.h> 26 #include "sframe-impl.h" 27 #include "swap.h" 28 29 /* Representation of SFrame FDE internal to libsframe. */ 30 typedef struct sframe_func_desc_entry_int 31 { 32 int64_t func_start_pc_offset; 33 uint32_t func_size; 34 uint32_t func_start_fre_off; 35 uint32_t func_num_fres; 36 uint8_t func_info; 37 uint8_t func_info2; 38 uint8_t func_rep_size; 39 } sframe_func_desc_entry_int; 40 41 struct sf_fde_tbl 42 { 43 unsigned int count; 44 unsigned int alloced; 45 sframe_func_desc_entry_int entry[1]; 46 }; 47 48 struct sf_fre_tbl 49 { 50 unsigned int count; 51 unsigned int alloced; 52 sframe_frame_row_entry entry[1]; 53 }; 54 55 #define _sf_printflike_(string_index,first_to_check) \ 56 __attribute__ ((__format__ (__printf__, (string_index), (first_to_check)))) 57 58 static void debug_printf (const char *, ...); 59 60 static int _sframe_debug; /* Control for printing out debug info. */ 61 62 #define SFRAME_FRE_ALLOC_LEN 64 63 static int number_of_entries = 64; 64 65 static void 66 sframe_init_debug (void) 67 { 68 static int inited; 69 70 if (!inited) 71 { 72 _sframe_debug = getenv ("SFRAME_DEBUG") != NULL; 73 inited = 1; 74 } 75 } 76 77 _sf_printflike_ (1, 2) 78 static void debug_printf (const char *format, ...) 79 { 80 if (_sframe_debug) 81 { 82 va_list args; 83 84 va_start (args, format); 85 vfprintf (stderr, format, args); 86 va_end (args); 87 } 88 } 89 90 /* Generate bitmask of given size in bytes. This is used for 91 some checks on the FRE start address. 92 SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ] 93 SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ] 94 SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ]. */ 95 #define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \ 96 (((uint64_t)1 << (size_in_bytes*8)) - 1) 97 98 /* Store the specified error code into errp if it is non-NULL. 99 Return SFRAME_ERR. */ 100 101 static int 102 sframe_set_errno (int *errp, int error) 103 { 104 if (errp != NULL) 105 *errp = error; 106 return SFRAME_ERR; 107 } 108 109 /* Store the specified error code into errp if it is non-NULL. 110 Return NULL. */ 111 112 static void * 113 sframe_ret_set_errno (int *errp, int error) 114 { 115 if (errp != NULL) 116 *errp = error; 117 return NULL; 118 } 119 120 /* Allocate space for NUM_FDES number of SFrame FDEs of type 121 sframe_func_desc_entry_int. This is version-unaware because this pertains 122 to libsframe's internal in-memory representation of SFrame FDE. */ 123 124 static int 125 sframe_fde_tbl_alloc (sf_fde_tbl **fde_tbl, unsigned int num_fdes) 126 { 127 size_t fidx_size = num_fdes * sizeof (sframe_func_desc_entry_int); 128 size_t fd_tbl_sz = (sizeof (sf_fde_tbl) + fidx_size); 129 130 *fde_tbl = malloc (fd_tbl_sz); 131 if (*fde_tbl == NULL) 132 return SFRAME_ERR; 133 134 (*fde_tbl)->alloced = num_fdes; 135 136 return 0; 137 } 138 139 /* Initialize libsframe's internal representation of SFrame FDEs. */ 140 141 static int 142 sframe_fde_tbl_init (sf_fde_tbl *fde_tbl, const char *fde_buf, 143 const char *fre_buf, size_t *fidx_size, 144 unsigned int num_fdes, uint8_t ver) 145 { 146 if (ver == SFRAME_VERSION_3 && SFRAME_VERSION == SFRAME_VERSION_3) 147 { 148 *fidx_size = num_fdes * sizeof (sframe_func_desc_idx_v3); 149 for (unsigned int i = 0; i < num_fdes; i++) 150 { 151 const sframe_func_desc_idx_v3 *fdep 152 = (sframe_func_desc_idx_v3 *)fde_buf + i; 153 fde_tbl->entry[i].func_start_pc_offset = fdep->sfdi_func_start_offset; 154 fde_tbl->entry[i].func_size = fdep->sfdi_func_size; 155 fde_tbl->entry[i].func_start_fre_off = fdep->sfdi_func_start_fre_off; 156 /* V3 organizes the following data closer to the SFrame FREs for the 157 function. Access them via the sfde_func_start_fre_off. */ 158 const sframe_func_desc_attr_v3 *fattr 159 = (sframe_func_desc_attr_v3 *)(fre_buf 160 + fdep->sfdi_func_start_fre_off); 161 fde_tbl->entry[i].func_num_fres = fattr->sfda_func_num_fres; 162 fde_tbl->entry[i].func_info = fattr->sfda_func_info; 163 fde_tbl->entry[i].func_info2 = fattr->sfda_func_info2; 164 fde_tbl->entry[i].func_rep_size = fattr->sfda_func_rep_size; 165 } 166 fde_tbl->count = num_fdes; 167 } 168 /* If ver is not the latest, read buffer manually and upgrade from 169 sframe_func_desc_entry_v2 to populate the sf_fde_tbl entries. */ 170 else if (ver == SFRAME_VERSION_2 && SFRAME_VERSION == SFRAME_VERSION_3) 171 { 172 *fidx_size = num_fdes * sizeof (sframe_func_desc_entry_v2); 173 for (unsigned int i = 0; i < num_fdes; i++) 174 { 175 const sframe_func_desc_entry_v2 *fdep 176 = (sframe_func_desc_entry_v2 *)fde_buf + i; 177 fde_tbl->entry[i].func_start_pc_offset 178 = fdep->sfde_func_start_address; 179 fde_tbl->entry[i].func_size = fdep->sfde_func_size; 180 fde_tbl->entry[i].func_start_fre_off = fdep->sfde_func_start_fre_off; 181 fde_tbl->entry[i].func_num_fres = fdep->sfde_func_num_fres; 182 fde_tbl->entry[i].func_info = fdep->sfde_func_info; 183 fde_tbl->entry[i].func_info2 = 0; 184 fde_tbl->entry[i].func_rep_size = fdep->sfde_func_rep_size; 185 } 186 fde_tbl->count = num_fdes; 187 } 188 else 189 { 190 /* Not possible ATM. */ 191 *fidx_size = 0; 192 return SFRAME_ERR; 193 } 194 195 return 0; 196 } 197 198 /* Get the SFrame header size. */ 199 200 static uint32_t 201 sframe_get_hdr_size (const sframe_header *sfh) 202 { 203 return SFRAME_V1_HDR_SIZE (*sfh); 204 } 205 206 /* Access functions for frame row entry data. */ 207 208 static uint8_t 209 sframe_fre_get_dataword_count (uint8_t fre_info) 210 { 211 return SFRAME_V1_FRE_OFFSET_COUNT (fre_info); 212 } 213 214 static uint8_t 215 sframe_fre_get_dataword_size (uint8_t fre_info) 216 { 217 return SFRAME_V1_FRE_OFFSET_SIZE (fre_info); 218 } 219 220 static bool 221 sframe_get_fre_ra_mangled_p (uint8_t fre_info) 222 { 223 return SFRAME_V1_FRE_MANGLED_RA_P (fre_info); 224 } 225 226 static bool 227 sframe_get_fre_ra_undefined_p (uint8_t fre_info) 228 { 229 return SFRAME_V2_FRE_RA_UNDEFINED_P (fre_info); 230 } 231 232 /* Access functions for info from function descriptor entry. */ 233 234 static uint32_t 235 sframe_get_fre_type (sframe_func_desc_entry_int *fdep) 236 { 237 uint32_t fre_type = 0; 238 if (fdep) 239 fre_type = SFRAME_V2_FUNC_FRE_TYPE (fdep->func_info); 240 return fre_type; 241 } 242 243 static uint32_t 244 sframe_get_fde_pc_type (sframe_func_desc_entry_int *fdep) 245 { 246 uint32_t fde_pc_type = 0; 247 if (fdep) 248 fde_pc_type = SFRAME_V2_FUNC_PC_TYPE (fdep->func_info); 249 return fde_pc_type; 250 } 251 252 /* Check if flipping is needed, based on ENDIAN. */ 253 254 static int 255 need_swapping (int endian) 256 { 257 unsigned int ui = 1; 258 char *c = (char *)&ui; 259 int is_little = (int)*c; 260 261 switch (endian) 262 { 263 case SFRAME_ABI_AARCH64_ENDIAN_LITTLE: 264 case SFRAME_ABI_AMD64_ENDIAN_LITTLE: 265 return !is_little; 266 case SFRAME_ABI_AARCH64_ENDIAN_BIG: 267 case SFRAME_ABI_S390X_ENDIAN_BIG: 268 return is_little; 269 default: 270 break; 271 } 272 273 return 0; 274 } 275 276 /* Flip the endianness of the SFrame header starting at BUF. 277 VER is the version of the SFrame data in the buffer. 278 279 Returns SFRAME_ERR if any error. If error code is returned, the flipped 280 header should not be used. */ 281 282 static int 283 flip_header (char *buf, uint8_t ver ATTRIBUTE_UNUSED) 284 { 285 /* SFrame header binary format has remained the same in SFRAME_VERSION_1, 286 SFRAME_VERSION_2. */ 287 sframe_header *sfh = (sframe_header *) buf; 288 swap_thing (sfh->sfh_preamble.sfp_magic); 289 swap_thing (sfh->sfh_preamble.sfp_version); 290 swap_thing (sfh->sfh_preamble.sfp_flags); 291 swap_thing (sfh->sfh_abi_arch); 292 swap_thing (sfh->sfh_cfa_fixed_fp_offset); 293 swap_thing (sfh->sfh_cfa_fixed_ra_offset); 294 swap_thing (sfh->sfh_auxhdr_len); 295 swap_thing (sfh->sfh_num_fdes); 296 swap_thing (sfh->sfh_num_fres); 297 swap_thing (sfh->sfh_fre_len); 298 swap_thing (sfh->sfh_fdeoff); 299 swap_thing (sfh->sfh_freoff); 300 301 /* Alert for missing functionatlity. Auxiliary header, if present, needs to 302 flipped based on per abi/arch semantics. */ 303 if (sfh->sfh_auxhdr_len) 304 return SFRAME_ERR; 305 306 return 0; 307 } 308 309 /* Endian flip the SFrame FDE at BUF (buffer size provided in BUF_SIZE), given 310 the SFrame version VER. Update the FDE_SIZE to the size of the SFrame FDE 311 flipped. 312 313 Return SFRAME_ERR if any error. If error code is returned, the flipped FDEP 314 should not be used. */ 315 316 static int 317 flip_fde_desc (char *buf, size_t buf_size, uint8_t ver) 318 { 319 if (ver == SFRAME_VERSION_3) 320 { 321 if (buf_size < sizeof (sframe_func_desc_idx_v3)) 322 return SFRAME_ERR; 323 324 sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *) buf; 325 swap_thing (fdep->sfdi_func_start_offset); 326 swap_thing (fdep->sfdi_func_size); 327 swap_thing (fdep->sfdi_func_start_fre_off); 328 } 329 else if (ver == SFRAME_VERSION_2) 330 { 331 if (buf_size < sizeof (sframe_func_desc_entry_v2)) 332 return SFRAME_ERR; 333 334 sframe_func_desc_entry_v2 *fdep = (sframe_func_desc_entry_v2 *) buf; 335 swap_thing (fdep->sfde_func_start_address); 336 swap_thing (fdep->sfde_func_size); 337 swap_thing (fdep->sfde_func_start_fre_off); 338 swap_thing (fdep->sfde_func_num_fres); 339 } 340 else 341 return SFRAME_ERR; 342 343 return 0; 344 } 345 346 static int 347 flip_fde_attr_v3 (char *buf, size_t buf_size) 348 { 349 if (buf_size < sizeof (sframe_func_desc_attr_v3)) 350 return SFRAME_ERR; 351 352 /* sfda_func_num_fres is the first member of sframe_func_desc_attr_v3. */ 353 struct { uint16_t x; } ATTRIBUTE_PACKED *p = (void*)buf; 354 swap_thing (p->x); 355 356 return 0; 357 } 358 /* Check if SFrame header has valid data. */ 359 360 static bool 361 sframe_header_sanity_check_p (const sframe_header *hp) 362 { 363 /* Check preamble is valid. */ 364 if (hp->sfh_preamble.sfp_magic != SFRAME_MAGIC 365 || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_1 366 && hp->sfh_preamble.sfp_version != SFRAME_VERSION_2 367 && hp->sfh_preamble.sfp_version != SFRAME_VERSION_3)) 368 return false; 369 370 /* Check flags (version-aware). 371 Do not validate V3 headers against V2 flag definitions, as V3 may 372 introduce new flags. */ 373 uint8_t valid_flags = SFRAME_V2_F_ALL_FLAGS; 374 if (hp->sfh_preamble.sfp_version == SFRAME_VERSION_3) 375 /* Replace with SFRAME_V3_F_ALL_FLAGS. */ 376 valid_flags = SFRAME_V3_F_ALL_FLAGS; 377 if (hp->sfh_preamble.sfp_flags & ~valid_flags) 378 return false; 379 380 /* Check offsets are valid. */ 381 if (hp->sfh_fdeoff > hp->sfh_freoff) 382 return false; 383 384 return true; 385 } 386 387 /* Flip the start address pointed to by FP. */ 388 389 static void 390 flip_fre_start_address (void *addr, uint32_t fre_type) 391 { 392 if (fre_type == SFRAME_FRE_TYPE_ADDR2) 393 { 394 struct { uint16_t x; } ATTRIBUTE_PACKED *p = addr; 395 swap_thing (p->x); 396 } 397 else if (fre_type == SFRAME_FRE_TYPE_ADDR4) 398 { 399 struct { uint32_t x; } ATTRIBUTE_PACKED *p = addr; 400 swap_thing (p->x); 401 } 402 } 403 404 static void 405 flip_fre_datawords (void *datawords, uint8_t dataword_size, 406 uint8_t dataword_cnt) 407 { 408 int j; 409 410 if (dataword_size == SFRAME_FRE_DATAWORD_2B) 411 { 412 struct { uint16_t x; } ATTRIBUTE_PACKED *p = datawords; 413 for (j = dataword_cnt; j > 0; p++, j--) 414 swap_thing (p->x); 415 } 416 else if (dataword_size == SFRAME_FRE_DATAWORD_4B) 417 { 418 struct { uint32_t x; } ATTRIBUTE_PACKED *p = datawords; 419 for (j = dataword_cnt; j > 0; p++, j--) 420 swap_thing (p->x); 421 } 422 } 423 424 /* Get the FRE start address size, given the FRE_TYPE. */ 425 426 static size_t 427 sframe_fre_start_addr_size (uint32_t fre_type) 428 { 429 size_t addr_size = 0; 430 switch (fre_type) 431 { 432 case SFRAME_FRE_TYPE_ADDR1: 433 addr_size = 1; 434 break; 435 case SFRAME_FRE_TYPE_ADDR2: 436 addr_size = 2; 437 break; 438 case SFRAME_FRE_TYPE_ADDR4: 439 addr_size = 4; 440 break; 441 default: 442 /* No other value is expected. */ 443 sframe_assert (0); 444 break; 445 } 446 return addr_size; 447 } 448 449 /* Check if the FREP has valid data. */ 450 451 static bool 452 sframe_fre_sanity_check_p (const sframe_frame_row_entry *frep) 453 { 454 uint8_t dataword_size, dataword_cnt; 455 uint8_t fre_info; 456 457 if (frep == NULL) 458 return false; 459 460 fre_info = frep->fre_info; 461 dataword_size = sframe_fre_get_dataword_size (fre_info); 462 463 if (dataword_size != SFRAME_FRE_DATAWORD_1B 464 && dataword_size != SFRAME_FRE_DATAWORD_2B 465 && dataword_size != SFRAME_FRE_DATAWORD_4B) 466 return false; 467 468 dataword_cnt = sframe_fre_get_dataword_count (fre_info); 469 if (dataword_cnt > MAX_NUM_DATAWORDS) 470 return false; 471 472 return true; 473 } 474 475 /* Get FRE_INFO's data words' size in bytes. */ 476 477 static size_t 478 sframe_fre_datawords_bytes_size (uint8_t fre_info) 479 { 480 uint8_t dataword_size, dataword_cnt; 481 482 dataword_size = sframe_fre_get_dataword_size (fre_info); 483 484 debug_printf ("dataword_size = %u\n", dataword_size); 485 486 dataword_cnt = sframe_fre_get_dataword_count (fre_info); 487 488 if (dataword_size == SFRAME_FRE_DATAWORD_2B 489 || dataword_size == SFRAME_FRE_DATAWORD_4B) /* 2 or 4 bytes. */ 490 return (dataword_cnt * (dataword_size * 2)); 491 492 return dataword_cnt; 493 } 494 495 /* Get total size in bytes to represent FREP in the binary format. This 496 includes the starting address, FRE info, and all the offsets. */ 497 498 static size_t 499 sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type) 500 { 501 if (frep == NULL) 502 return 0; 503 504 uint8_t fre_info = frep->fre_info; 505 size_t addr_size = sframe_fre_start_addr_size (fre_type); 506 507 return (addr_size + sizeof (frep->fre_info) 508 + sframe_fre_datawords_bytes_size (fre_info)); 509 } 510 511 /* Get total size in bytes in the SFrame FRE at FRE_BUF location, given the 512 type of FRE as FRE_TYPE. */ 513 514 static size_t 515 sframe_buf_fre_entry_size (const char *fre_buf, uint32_t fre_type) 516 { 517 if (fre_buf == NULL) 518 return 0; 519 520 size_t addr_size = sframe_fre_start_addr_size (fre_type); 521 uint8_t fre_info = *(uint8_t *)(fre_buf + addr_size); 522 523 return (addr_size + sizeof (fre_info) 524 + sframe_fre_datawords_bytes_size (fre_info)); 525 } 526 /* Get the function descriptor entry at index FUNC_IDX in the decoder 527 context CTX. */ 528 529 static sframe_func_desc_entry_int * 530 sframe_decoder_get_funcdesc_at_index (const sframe_decoder_ctx *ctx, 531 uint32_t func_idx) 532 { 533 sframe_func_desc_entry_int *fdep; 534 uint32_t num_fdes; 535 int err; 536 537 num_fdes = sframe_decoder_get_num_fidx (ctx); 538 if (num_fdes == 0 539 || func_idx >= num_fdes 540 || ctx->sfd_funcdesc == NULL 541 || ctx->sfd_funcdesc->count <= func_idx) 542 return sframe_ret_set_errno (&err, SFRAME_ERR_DCTX_INVAL); 543 544 fdep = &ctx->sfd_funcdesc->entry[func_idx]; 545 return fdep; 546 } 547 548 /* Get the offset of the start PC of the SFrame FDE at FUNC_IDX from the start 549 of the SFrame section. This section-relative offset is used within 550 libsframe for sorting the SFrame FDEs, and also information lookup routines 551 like sframe_find_fre. 552 553 If FUNC_IDX is not a valid index in the given decoder object, returns 0. */ 554 555 static int64_t 556 sframe_decoder_get_secrel_func_start_addr (const sframe_decoder_ctx *dctx, 557 uint32_t func_idx) 558 { 559 int err = 0; 560 int32_t offsetof_fde_in_sec 561 = sframe_decoder_get_offsetof_fde_start_addr (dctx, func_idx, &err); 562 /* If func_idx is not a valid index, return 0. */ 563 if (err) 564 return 0; 565 566 const sframe_func_desc_entry_int *fdep = &dctx->sfd_funcdesc->entry[func_idx]; 567 int64_t func_start_pc_offset = fdep->func_start_pc_offset; 568 569 return func_start_pc_offset + offsetof_fde_in_sec; 570 } 571 572 /* Check whether for the given FDEP, the SFrame Frame Row Entry identified via 573 the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace 574 information for the PC. */ 575 576 static bool 577 sframe_fre_check_range_p (const sframe_decoder_ctx *dctx, uint32_t func_idx, 578 uint32_t start_ip_offset, uint32_t end_ip_offset, 579 int64_t pc) 580 { 581 sframe_func_desc_entry_int *fdep; 582 int64_t func_start_pc_offset; 583 uint8_t rep_block_size; 584 uint32_t pc_type; 585 uint32_t pc_offset; 586 bool mask_p; 587 588 fdep = &dctx->sfd_funcdesc->entry[func_idx]; 589 func_start_pc_offset = sframe_decoder_get_secrel_func_start_addr (dctx, 590 func_idx); 591 pc_type = sframe_get_fde_pc_type (fdep); 592 mask_p = (pc_type == SFRAME_V3_FDE_PCTYPE_MASK); 593 rep_block_size = fdep->func_rep_size; 594 595 if (func_start_pc_offset > pc) 596 return false; 597 598 /* Given func_start_addr <= pc, pc - func_start_addr must be positive. */ 599 pc_offset = pc - func_start_pc_offset; 600 /* For SFrame FDEs encoding information for repetitive pattern of insns, 601 masking with the rep_block_size is necessary to find the matching FRE. */ 602 if (mask_p) 603 pc_offset = pc_offset % rep_block_size; 604 605 return (start_ip_offset <= pc_offset) && (end_ip_offset >= pc_offset); 606 } 607 608 /* Read the on-disk SFrame FDE from location BUF of size in bytes equal to 609 BUF_SIZE. 610 611 Return SFRAME_ERR if any error. If error code is returned, the read values 612 should not be used. */ 613 614 static int 615 sframe_decode_fde_desc_v2 (const char *buf, size_t buf_size, 616 uint32_t *num_fres, uint32_t *fre_type, 617 uint32_t *fre_offset) 618 { 619 if (buf_size < sizeof (sframe_func_desc_entry_v2)) 620 return SFRAME_ERR; 621 622 sframe_func_desc_entry_v2 *fdep = (sframe_func_desc_entry_v2 *) buf; 623 *num_fres = fdep->sfde_func_num_fres; 624 *fre_type = SFRAME_V2_FUNC_FRE_TYPE (fdep->sfde_func_info); 625 *fre_offset = fdep->sfde_func_start_fre_off; 626 627 return 0; 628 } 629 630 /* Read the on-disk SFrame FDE from location BUF of size in bytes equal to 631 BUF_SIZE. 632 633 Return SFRAME_ERR if any error. If error code is returned, the read values 634 should not be used. */ 635 636 static int 637 sframe_decode_fde_idx_v3 (const char *buf, size_t buf_size, 638 uint32_t *fre_offset) 639 { 640 if (buf_size < sizeof (sframe_func_desc_idx_v3)) 641 return SFRAME_ERR; 642 643 sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *) buf; 644 *fre_offset = fdep->sfdi_func_start_fre_off; 645 646 return 0; 647 } 648 649 static int 650 sframe_decode_fde_attr_v3 (const char *buf, size_t buf_size, 651 uint16_t *num_fres, uint32_t *fre_type) 652 { 653 if (buf_size < sizeof (sframe_func_desc_attr_v3)) 654 return SFRAME_ERR; 655 656 const sframe_func_desc_attr_v3 *fdap = (sframe_func_desc_attr_v3 *) buf; 657 *num_fres = fdap->sfda_func_num_fres; 658 *fre_type = SFRAME_V3_FDE_FRE_TYPE (fdap->sfda_func_info); 659 return 0; 660 } 661 662 static int 663 flip_fre (char *fp, size_t fp_size, uint32_t fre_type, size_t *fre_size) 664 { 665 uint8_t fre_info; 666 uint8_t dataword_size, dataword_cnt; 667 size_t addr_size, fre_info_size, datawords_bytes_size; 668 int err = 0; 669 670 if (fre_size == NULL) 671 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 672 673 addr_size = sframe_fre_start_addr_size (fre_type); 674 if (addr_size > fp_size) 675 return SFRAME_ERR; 676 flip_fre_start_address (fp, fre_type); 677 678 /* Advance the buffer pointer to where the FRE info is. */ 679 fp += addr_size; 680 fp_size -= addr_size; 681 682 /* FRE info is uint8_t. No need to flip. */ 683 fre_info_size = sizeof (uint8_t); 684 if (fre_info_size > fp_size) 685 return SFRAME_ERR; 686 fre_info = *(uint8_t*)fp; 687 dataword_size = sframe_fre_get_dataword_size (fre_info); 688 dataword_cnt = sframe_fre_get_dataword_count (fre_info); 689 690 /* Advance the buffer pointer to where the stack offsets are. */ 691 fp += fre_info_size; 692 fp_size -= fre_info_size; 693 datawords_bytes_size = sframe_fre_datawords_bytes_size (fre_info); 694 if (datawords_bytes_size > fp_size) 695 return SFRAME_ERR; 696 flip_fre_datawords (fp, dataword_size, dataword_cnt); 697 698 *fre_size = addr_size + fre_info_size + datawords_bytes_size; 699 700 return 0; 701 } 702 703 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE. 704 The SFrame header in the FRAME_BUF must be endian flipped prior to 705 calling flip_sframe. 706 707 Endian flipping at decode time vs encode time have different needs. At 708 encode time, the frame_buf is in host endianness, and hence, values should 709 be read up before the buffer is changed to foreign endianness. This change 710 of behaviour is specified via TO_FOREIGN arg. 711 712 If an error code is returned, the buffer should not be used. */ 713 714 static int 715 flip_sframe_fdes_with_fres_v2 (char *frame_buf, size_t buf_size, 716 uint32_t to_foreign) 717 { 718 char *fp = NULL; 719 uint32_t num_fres = 0; 720 uint32_t fre_type = 0; 721 uint32_t fre_offset = 0; 722 size_t esz = 0; 723 int err = 0; 724 /* For error checking. */ 725 size_t fde_bytes_flipped = 0; 726 size_t fre_bytes_flipped = 0; 727 728 /* Header must be in host endianness at this time. */ 729 const sframe_header *ihp = (sframe_header *)frame_buf; 730 731 if (!sframe_header_sanity_check_p (ihp)) 732 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL); 733 734 /* The contents of the SFrame header are safe to read. Get the number of 735 FDEs and the first FDE in the buffer. */ 736 size_t hdrsz = sframe_get_hdr_size (ihp); 737 uint32_t num_fdes = ihp->sfh_num_fdes; 738 uint8_t ver = ihp->sfh_preamble.sfp_version; 739 char *fdes = frame_buf + hdrsz + ihp->sfh_fdeoff; 740 char *fres = frame_buf + hdrsz + ihp->sfh_freoff; 741 const char *buf_end = frame_buf + buf_size; 742 743 unsigned int i = 0, j = 0; 744 unsigned int prev_frep_index = 0; 745 size_t fsz = sizeof (sframe_func_desc_entry_v2); 746 for (i = 0; i < num_fdes; fdes += fsz, i++) 747 { 748 if (fdes >= buf_end) 749 goto bad; 750 751 /* Handle FDE. */ 752 if (to_foreign && sframe_decode_fde_desc_v2 (fdes, buf_end - fdes, 753 &num_fres, &fre_type, 754 &fre_offset)) 755 goto bad; 756 757 if (flip_fde_desc (fdes, buf_end - fdes, ver)) 758 goto bad; 759 760 if (!to_foreign && sframe_decode_fde_desc_v2 (fdes, buf_end - fdes, 761 &num_fres, &fre_type, 762 &fre_offset)) 763 goto bad; 764 765 fde_bytes_flipped += fsz; 766 767 /* Handle FREs. */ 768 fp = fres + fre_offset; 769 for (; j < prev_frep_index + num_fres; j++) 770 { 771 if (flip_fre (fp, buf_end - fp, fre_type, &esz)) 772 goto bad; 773 fre_bytes_flipped += esz; 774 fp += esz; 775 } 776 prev_frep_index = j; 777 } 778 779 /* All FDEs must have been endian flipped by now. */ 780 if (i != num_fdes || fde_bytes_flipped > ihp->sfh_freoff - ihp->sfh_fdeoff) 781 goto bad; 782 783 /* All FREs must have been endian flipped by now. */ 784 if (j != ihp->sfh_num_fres || fre_bytes_flipped > ihp->sfh_fre_len) 785 goto bad; 786 787 /* Optional trailing section padding. */ 788 size_t frame_size = hdrsz + ihp->sfh_freoff + fre_bytes_flipped; 789 for (fp = frame_buf + frame_size; fp < frame_buf + buf_size; fp++) 790 if (*fp != '\0') 791 goto bad; 792 793 /* Done. */ 794 return 0; 795 bad: 796 return SFRAME_ERR; 797 } 798 799 /* Endian flip the contents of FRAME_BUF of size BUF_SIZE. 800 The SFrame header in the FRAME_BUF must be endian flipped prior to 801 calling flip_sframe_fdes_with_fres_v3. 802 803 Endian flipping at decode time vs encode time have different needs. At 804 encode time, the frame_buf is in host endianness, and hence, values should 805 be read up before the buffer is changed to foreign endianness. This change 806 of behaviour is specified via TO_FOREIGN arg. 807 808 If an error code is returned, the buffer should not be used. */ 809 810 static int 811 flip_sframe_fdes_with_fres_v3 (char *frame_buf, size_t buf_size, 812 uint32_t to_foreign) 813 { 814 char *fp = NULL; 815 uint16_t num_fres = 0; 816 uint32_t fre_type = 0; 817 uint32_t fre_offset = 0; 818 size_t esz = 0; 819 int err = 0; 820 /* For error checking. */ 821 size_t fde_bytes_flipped = 0; 822 size_t fre_bytes_flipped = 0; 823 824 /* Header must be in host endianness at this time. */ 825 const sframe_header *ihp = (sframe_header *)frame_buf; 826 827 if (!sframe_header_sanity_check_p (ihp)) 828 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL); 829 830 /* The contents of the SFrame header are safe to read. Get the number of 831 FDEs and the first FDE in the buffer. */ 832 size_t hdrsz = sframe_get_hdr_size (ihp); 833 uint32_t num_fdes = ihp->sfh_num_fdes; 834 uint8_t ver = ihp->sfh_preamble.sfp_version; 835 char *fdes = frame_buf + hdrsz + ihp->sfh_fdeoff; 836 char *fres = frame_buf + hdrsz + ihp->sfh_freoff; 837 const char *buf_end = frame_buf + buf_size; 838 839 unsigned int i = 0, j = 0; 840 unsigned int prev_frep_index = 0; 841 size_t fsz = sizeof (sframe_func_desc_idx_v3); 842 for (i = 0; i < num_fdes; fdes += fsz, i++) 843 { 844 if (fdes >= buf_end) 845 goto bad; 846 847 /* Handle FDE. */ 848 if (to_foreign && sframe_decode_fde_idx_v3 (fdes, buf_end - fdes, 849 &fre_offset)) 850 goto bad; 851 852 if (flip_fde_desc (fdes, buf_end - fdes, ver)) 853 goto bad; 854 855 if (!to_foreign && sframe_decode_fde_idx_v3 (fdes, buf_end - fdes, 856 &fre_offset)) 857 goto bad; 858 859 fde_bytes_flipped += fsz; 860 861 /* Handle FDE attr (only in V3). */ 862 fp = fres + fre_offset; 863 if (to_foreign && sframe_decode_fde_attr_v3 (fp, buf_end - fp, 864 &num_fres, &fre_type)) 865 goto bad; 866 867 if (flip_fde_attr_v3 (fp, buf_end - fp)) 868 goto bad; 869 870 fre_bytes_flipped += sizeof (sframe_func_desc_attr_v3); 871 872 if (!to_foreign && sframe_decode_fde_attr_v3 (fp, buf_end - fp, 873 &num_fres, &fre_type)) 874 goto bad; 875 876 /* Handle FREs. */ 877 fp += sizeof (sframe_func_desc_attr_v3); 878 for (; j < prev_frep_index + num_fres; j++) 879 { 880 if (flip_fre (fp, buf_end - fp, fre_type, &esz)) 881 goto bad; 882 fre_bytes_flipped += esz; 883 fp += esz; 884 } 885 prev_frep_index = j; 886 } 887 888 /* All FDEs must have been endian flipped by now. */ 889 if (i != num_fdes || fde_bytes_flipped > ihp->sfh_freoff - ihp->sfh_fdeoff) 890 goto bad; 891 892 /* All FREs must have been endian flipped by now. */ 893 if (j != ihp->sfh_num_fres || fre_bytes_flipped > ihp->sfh_fre_len) 894 goto bad; 895 896 /* Optional trailing section padding. */ 897 size_t frame_size = hdrsz + ihp->sfh_freoff + fre_bytes_flipped; 898 for (fp = frame_buf + frame_size; fp < frame_buf + buf_size; fp++) 899 if (*fp != '\0') 900 goto bad; 901 902 /* Done. */ 903 return 0; 904 bad: 905 return SFRAME_ERR; 906 } 907 908 static int 909 flip_sframe (char *frame_buf, size_t buf_size, uint32_t to_foreign) 910 { 911 int err = 0; 912 913 /* Header must be in host endianness at this time. */ 914 const sframe_header *ihp = (sframe_header *)frame_buf; 915 if (!sframe_header_sanity_check_p (ihp)) 916 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL); 917 uint8_t ver = ihp->sfh_preamble.sfp_version; 918 919 if (ver == SFRAME_VERSION_3) 920 err = flip_sframe_fdes_with_fres_v3 (frame_buf, buf_size, to_foreign); 921 else if (ver == SFRAME_VERSION_2) 922 err = flip_sframe_fdes_with_fres_v2 (frame_buf, buf_size, to_foreign); 923 else 924 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL); 925 926 if (err) 927 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL); 928 929 /* Success. */ 930 return 0; 931 } 932 933 /* Expands the memory allocated for the SFrame Frame Row Entry (FRE) table 934 FRE_TBL. This function is called when the current FRE buffer is 935 insufficient and more stack trace data in the form of COUNT number of SFrame 936 FREs need to be added to the SFrame section. 937 938 Updates ERRP with 0 on success, or an SFrame error code on failure (e.g., 939 memory allocation error). */ 940 941 static sf_fre_tbl * 942 sframe_grow_fre_tbl (sf_fre_tbl *fre_tbl, uint32_t count, int *errp) 943 { 944 size_t fre_tbl_sz = 0; 945 /* Ensure buffer for at least COUNT number of elements. */ 946 uint32_t grow_count = SFRAME_FRE_ALLOC_LEN + count; 947 sf_fre_tbl *new_tbl = NULL; 948 949 if (fre_tbl == NULL) 950 { 951 fre_tbl_sz = (sizeof (sf_fre_tbl) 952 + (grow_count * sizeof (sframe_frame_row_entry))); 953 new_tbl = malloc (fre_tbl_sz); 954 if (new_tbl == NULL) 955 { 956 sframe_set_errno (errp, SFRAME_ERR_NOMEM); 957 goto bad; 958 } 959 960 memset (new_tbl, 0, fre_tbl_sz); 961 new_tbl->alloced = grow_count; 962 } 963 else if (fre_tbl->count + count >= fre_tbl->alloced) 964 { 965 uint32_t new_len = fre_tbl->alloced + grow_count; 966 fre_tbl_sz = (sizeof (sf_fre_tbl) 967 + (new_len * sizeof (sframe_frame_row_entry))); 968 void *tmp = realloc (fre_tbl, fre_tbl_sz); 969 if (tmp == NULL) 970 { 971 sframe_set_errno (errp, SFRAME_ERR_NOMEM); 972 goto bad; 973 } 974 new_tbl = tmp; 975 976 memset (&new_tbl->entry[new_tbl->alloced], 0, 977 grow_count * sizeof (sframe_frame_row_entry)); 978 new_tbl->alloced += grow_count; 979 } 980 981 bad: 982 return new_tbl; 983 } 984 985 /* The SFrame Decoder. */ 986 987 /* Get SFrame header from the given decoder context DCTX. */ 988 989 static const sframe_header * 990 sframe_decoder_get_header (const sframe_decoder_ctx *dctx) 991 { 992 const sframe_header *hp = NULL; 993 if (dctx != NULL) 994 hp = &dctx->sfd_header; 995 return hp; 996 } 997 998 /* Compare function for qsort'ing the FDE table. */ 999 1000 static int 1001 fde_func (const void *p1, const void *p2) 1002 { 1003 const sframe_func_desc_entry_int *aa = p1; 1004 const sframe_func_desc_entry_int *bb = p2; 1005 1006 if (aa->func_start_pc_offset < bb->func_start_pc_offset) 1007 return -1; 1008 else if (aa->func_start_pc_offset > bb->func_start_pc_offset) 1009 return 1; 1010 return 0; 1011 } 1012 1013 /* Get IDX'th offset from FRE. Set errp as applicable. */ 1014 1015 static int32_t 1016 sframe_get_fre_offset (const sframe_frame_row_entry *fre, int idx, int *errp) 1017 { 1018 uint8_t dataword_cnt, dataword_size; 1019 1020 if (fre == NULL || !sframe_fre_sanity_check_p (fre)) 1021 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL); 1022 1023 dataword_cnt = sframe_fre_get_dataword_count (fre->fre_info); 1024 dataword_size = sframe_fre_get_dataword_size (fre->fre_info); 1025 1026 if (dataword_cnt < idx + 1) 1027 return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT); 1028 1029 if (errp) 1030 *errp = 0; /* Offset Valid. */ 1031 1032 if (dataword_size == SFRAME_FRE_DATAWORD_1B) 1033 { 1034 int8_t *offsets = (int8_t *)fre->fre_datawords; 1035 return offsets[idx]; 1036 } 1037 else if (dataword_size == SFRAME_FRE_DATAWORD_2B) 1038 { 1039 int16_t *offsets = (int16_t *)fre->fre_datawords; 1040 return offsets[idx]; 1041 } 1042 else 1043 { 1044 int32_t *offsets = (int32_t *)fre->fre_datawords; 1045 return offsets[idx]; 1046 } 1047 } 1048 1049 /* Get IDX'th data word as unsigned data from FRE. Set errp as applicable. */ 1050 1051 uint32_t 1052 sframe_get_fre_udata (const sframe_frame_row_entry *fre, int idx, int *errp) 1053 { 1054 uint8_t dataword_cnt, dataword_size; 1055 1056 if (fre == NULL || !sframe_fre_sanity_check_p (fre)) 1057 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL); 1058 1059 dataword_cnt = sframe_fre_get_dataword_count (fre->fre_info); 1060 dataword_size = sframe_fre_get_dataword_size (fre->fre_info); 1061 1062 if (dataword_cnt < idx + 1) 1063 return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT); 1064 1065 if (errp) 1066 *errp = 0; /* Offset Valid. */ 1067 1068 if (dataword_size == SFRAME_FRE_DATAWORD_1B) 1069 { 1070 uint8_t *datawords = (uint8_t *)fre->fre_datawords; 1071 return datawords[idx]; 1072 } 1073 else if (dataword_size == SFRAME_FRE_DATAWORD_2B) 1074 { 1075 uint16_t *datawords = (uint16_t *)fre->fre_datawords; 1076 return datawords[idx]; 1077 } 1078 else 1079 { 1080 uint32_t *datawords = (uint32_t *)fre->fre_datawords; 1081 return datawords[idx]; 1082 } 1083 } 1084 1085 /* Free the decoder context. */ 1086 1087 void 1088 sframe_decoder_free (sframe_decoder_ctx **dctxp) 1089 { 1090 if (dctxp != NULL) 1091 { 1092 sframe_decoder_ctx *dctx = *dctxp; 1093 if (dctx == NULL) 1094 return; 1095 1096 if (dctx->sfd_funcdesc != NULL) 1097 { 1098 free (dctx->sfd_funcdesc); 1099 dctx->sfd_funcdesc = NULL; 1100 } 1101 if (dctx->sfd_fres != NULL) 1102 { 1103 free (dctx->sfd_fres); 1104 dctx->sfd_fres = NULL; 1105 } 1106 if (dctx->sfd_buf != NULL) 1107 { 1108 free (dctx->sfd_buf); 1109 dctx->sfd_buf = NULL; 1110 } 1111 1112 free (*dctxp); 1113 *dctxp = NULL; 1114 } 1115 } 1116 1117 /* Create an FDE function info byte given an FRE_TYPE and an FDE_TYPE. */ 1118 /* FIXME API for linker. Revisit if its better placed somewhere else? */ 1119 1120 unsigned char 1121 sframe_fde_create_func_info (uint32_t fre_type, 1122 uint32_t fde_type) 1123 { 1124 unsigned char func_info; 1125 sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1 1126 || fre_type == SFRAME_FRE_TYPE_ADDR2 1127 || fre_type == SFRAME_FRE_TYPE_ADDR4); 1128 sframe_assert (fde_type == SFRAME_V3_FDE_PCTYPE_INC 1129 || fde_type == SFRAME_V3_FDE_PCTYPE_MASK); 1130 func_info = SFRAME_V2_FUNC_INFO (fde_type, fre_type); 1131 return func_info; 1132 } 1133 1134 /* Get the FRE type given the function size. */ 1135 /* FIXME API for linker. Revisit if its better placed somewhere else? */ 1136 1137 uint32_t 1138 sframe_calc_fre_type (size_t func_size) 1139 { 1140 uint32_t fre_type = 0; 1141 if (func_size < SFRAME_FRE_TYPE_ADDR1_LIMIT) 1142 fre_type = SFRAME_FRE_TYPE_ADDR1; 1143 else if (func_size < SFRAME_FRE_TYPE_ADDR2_LIMIT) 1144 fre_type = SFRAME_FRE_TYPE_ADDR2; 1145 /* Adjust the check a bit so that it remains warning-free but meaningful 1146 on 32-bit systems. */ 1147 else if (func_size <= (size_t) (SFRAME_FRE_TYPE_ADDR4_LIMIT - 1)) 1148 fre_type = SFRAME_FRE_TYPE_ADDR4; 1149 return fre_type; 1150 } 1151 1152 /* Get the base reg id from the FRE info. Set errp if failure. */ 1153 1154 uint8_t 1155 sframe_fre_get_base_reg_id (const sframe_frame_row_entry *fre, int *errp) 1156 { 1157 if (fre == NULL) 1158 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL); 1159 1160 uint8_t fre_info = fre->fre_info; 1161 return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info); 1162 } 1163 1164 /* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */ 1165 1166 int32_t 1167 sframe_fre_get_cfa_offset (const sframe_decoder_ctx *dctx, 1168 const sframe_frame_row_entry *fre, 1169 uint32_t fde_type, 1170 int *errp) 1171 { 1172 int err; 1173 bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX); 1174 uint32_t idx = flex_p ? 1 : 0; 1175 int32_t offset = sframe_get_fre_offset (fre, idx, &err); 1176 1177 /* For s390x undo adjustment of CFA offset (to enable 8-bit offsets). */ 1178 if (!err 1179 && sframe_decoder_get_abi_arch (dctx) == SFRAME_ABI_S390X_ENDIAN_BIG) 1180 offset = SFRAME_V2_S390X_CFA_OFFSET_DECODE (offset); 1181 1182 if (errp) 1183 *errp = err; 1184 return offset; 1185 } 1186 1187 /* Get the FP offset from the FRE. If the offset is invalid, sets errp. */ 1188 1189 int32_t 1190 sframe_fre_get_fp_offset (const sframe_decoder_ctx *dctx, 1191 const sframe_frame_row_entry *fre, 1192 uint32_t fde_type, 1193 int *errp) 1194 { 1195 int fp_err = 0; 1196 int8_t fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (dctx); 1197 bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX); 1198 1199 /* Initialize fp_offset_idx for default FDEs. In some ABIs, the stack offset 1200 to recover RA (using the CFA) from is fixed (like AMD64). In such cases, 1201 the stack offset to recover FP will appear at the second index. */ 1202 uint32_t fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx) 1203 != SFRAME_CFA_FIXED_RA_INVALID) 1204 ? SFRAME_FRE_RA_OFFSET_IDX 1205 : SFRAME_FRE_FP_OFFSET_IDX); 1206 if (flex_p) 1207 { 1208 uint32_t flex_ra_reg_data 1209 = sframe_get_fre_udata (fre, SFRAME_FRE_RA_OFFSET_IDX * 2, errp); 1210 /* In presence of RA padding SFRAME_FRE_RA_OFFSET_INVALID (instead of RA 1211 offsets), adjust the expected index of the FP offset. */ 1212 if (errp && *errp == 0 1213 && flex_ra_reg_data == SFRAME_FRE_RA_OFFSET_INVALID) 1214 fp_offset_idx = SFRAME_FRE_FP_OFFSET_IDX * 2; 1215 else 1216 fp_offset_idx = SFRAME_FRE_FP_OFFSET_IDX * 2 + 1; 1217 } 1218 1219 /* NB: This errp must be retained if returning fp_offset. */ 1220 int32_t fp_offset = sframe_get_fre_offset (fre, fp_offset_idx, &fp_err); 1221 1222 /* If the FP offset is not being tracked, return the fixed FP offset from the 1223 SFrame header: 1224 - For default FDEs (!flex_p) 1225 - For flex FDEs, if there were no FP offsets found. */ 1226 if ((!flex_p || (flex_p && fp_err)) 1227 && fixed_fp_offset != SFRAME_CFA_FIXED_FP_INVALID 1228 && !sframe_get_fre_ra_undefined_p (fre->fre_info)) 1229 { 1230 if (errp) 1231 *errp = 0; 1232 return fixed_fp_offset; 1233 } 1234 1235 if (errp) 1236 *errp = fp_err; 1237 return fp_offset; 1238 } 1239 1240 /* Get the RA offset from the FRE. If the offset is invalid, sets errp. */ 1241 1242 int32_t 1243 sframe_fre_get_ra_offset (const sframe_decoder_ctx *dctx, 1244 const sframe_frame_row_entry *fre, 1245 uint32_t fde_type, 1246 int *errp) 1247 { 1248 int ra_err = 0; 1249 int8_t fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (dctx); 1250 bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX); 1251 1252 uint32_t ra_offset_idx = (flex_p 1253 ? SFRAME_FRE_RA_OFFSET_IDX * 2 + 1 1254 : SFRAME_FRE_RA_OFFSET_IDX); 1255 /* NB: This errp must be retained if returning ra_offset. */ 1256 int32_t ra_offset = sframe_get_fre_offset (fre, ra_offset_idx, &ra_err); 1257 1258 /* For ABIs where RA offset is not being tracked, return the fixed RA offset 1259 specified in the the SFrame header, when: 1260 - for default FDEs (!flex_p) 1261 - for flex FDEs, if RA offset is solely padding or not present. */ 1262 if ((!flex_p || (flex_p && ra_err)) 1263 && fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID 1264 && !sframe_get_fre_ra_undefined_p (fre->fre_info)) 1265 { 1266 if (errp) 1267 *errp = 0; 1268 return fixed_ra_offset; 1269 } 1270 1271 /* Otherwise, return the RA offset from the FRE. The corresponding errp was 1272 set earlier. */ 1273 if (errp) 1274 *errp = ra_err; 1275 return ra_offset; 1276 } 1277 1278 /* Get whether the RA is mangled. */ 1279 1280 bool 1281 sframe_fre_get_ra_mangled_p (const sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED, 1282 const sframe_frame_row_entry *fre, int *errp) 1283 { 1284 if (fre == NULL || !sframe_fre_sanity_check_p (fre)) 1285 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL); 1286 1287 return sframe_get_fre_ra_mangled_p (fre->fre_info); 1288 } 1289 1290 /* Get whether the RA is undefined (i.e. outermost frame). */ 1291 1292 bool 1293 sframe_fre_get_ra_undefined_p (const sframe_decoder_ctx *dctx ATTRIBUTE_UNUSED, 1294 const sframe_frame_row_entry *fre, int *errp) 1295 { 1296 if (fre == NULL || !sframe_fre_sanity_check_p (fre)) 1297 return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL); 1298 1299 return sframe_get_fre_ra_undefined_p (fre->fre_info); 1300 } 1301 1302 static int 1303 sframe_frame_row_entry_copy (sframe_frame_row_entry *dst, 1304 sframe_frame_row_entry *src) 1305 { 1306 int err = 0; 1307 1308 if (dst == NULL || src == NULL) 1309 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 1310 1311 memcpy (dst, src, sizeof (sframe_frame_row_entry)); 1312 return 0; 1313 } 1314 1315 /* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk 1316 binary format, given the FRE_TYPE. Updates the FRE_START_ADDR. 1317 1318 Returns 0 on success, SFRAME_ERR otherwise. */ 1319 1320 static int 1321 sframe_decode_fre_start_address (const void *fre_buf, 1322 uint32_t *fre_start_addr, 1323 uint32_t fre_type) 1324 { 1325 uint32_t saddr = 0; 1326 int err = 0; 1327 1328 if (fre_type == SFRAME_FRE_TYPE_ADDR1) 1329 { 1330 const uint8_t *uc = fre_buf; 1331 saddr = *uc; 1332 } 1333 else if (fre_type == SFRAME_FRE_TYPE_ADDR2) 1334 { 1335 /* SFrame is an unaligned on-disk format. See PR libsframe/29856. */ 1336 const struct { uint16_t x; } ATTRIBUTE_PACKED *p = fre_buf; 1337 saddr = p->x; 1338 } 1339 else if (fre_type == SFRAME_FRE_TYPE_ADDR4) 1340 { 1341 const struct { uint32_t x; } ATTRIBUTE_PACKED *p = fre_buf; 1342 saddr = p->x; 1343 } 1344 else 1345 sframe_set_errno (&err, SFRAME_ERR_INVAL); 1346 1347 *fre_start_addr = saddr; 1348 return err; 1349 } 1350 1351 /* Decode a frame row entry FRE which starts at location FRE_BUF. The function 1352 updates ESZ to the size of the FRE as stored in the binary format. 1353 1354 This function works closely with the SFrame binary format. 1355 1356 Returns SFRAME_ERR if failure. */ 1357 1358 static int 1359 sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre, 1360 uint32_t fre_type, size_t *esz) 1361 { 1362 int err = 0; 1363 const char *datawords = NULL; 1364 size_t datawords_sz; 1365 size_t addr_size; 1366 size_t fre_size; 1367 1368 if (fre_buf == NULL || fre == NULL || esz == NULL) 1369 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 1370 1371 /* Copy over the FRE start address. */ 1372 sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type); 1373 1374 addr_size = sframe_fre_start_addr_size (fre_type); 1375 fre->fre_info = *(uint8_t *)(fre_buf + addr_size); 1376 /* Sanity check as the API works closely with the binary format. */ 1377 sframe_assert (sizeof (fre->fre_info) == sizeof (uint8_t)); 1378 1379 /* Cleanup the space for fre_datawords first, then copy over the valid 1380 bytes. */ 1381 memset (fre->fre_datawords, 0, MAX_DATAWORD_BYTES); 1382 /* Get offsets size. */ 1383 datawords_sz = sframe_fre_datawords_bytes_size (fre->fre_info); 1384 datawords = fre_buf + addr_size + sizeof (fre->fre_info); 1385 memcpy (fre->fre_datawords, datawords, datawords_sz); 1386 1387 /* The FRE has been decoded. Use it to perform one last sanity check. */ 1388 fre_size = sframe_fre_entry_size (fre, fre_type); 1389 sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info) 1390 + datawords_sz)); 1391 *esz = fre_size; 1392 1393 return 0; 1394 } 1395 1396 /* Decode the specified SFrame buffer SF_BUF of size SF_SIZE and return the 1397 new SFrame decoder context. 1398 1399 Sets ERRP for the caller if any error. Frees up the allocated memory in 1400 case of error. */ 1401 1402 sframe_decoder_ctx * 1403 sframe_decode (const char *sf_buf, size_t sf_size, int *errp) 1404 { 1405 const sframe_preamble *sfp; 1406 size_t hdrsz; 1407 const sframe_header *dhp; 1408 sframe_decoder_ctx *dctx; 1409 char *frame_buf; 1410 char *tempbuf = NULL; 1411 1412 size_t fidx_size; 1413 uint32_t fre_bytes; 1414 int foreign_endian = 0; 1415 1416 sframe_init_debug (); 1417 1418 if ((sf_buf == NULL) || (!sf_size)) 1419 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL); 1420 else if (sf_size < sizeof (sframe_header)) 1421 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 1422 1423 sfp = (const sframe_preamble *) sf_buf; 1424 1425 debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n", 1426 sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags); 1427 1428 /* Check for foreign endianness. */ 1429 if (sfp->sfp_magic != SFRAME_MAGIC) 1430 { 1431 if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC)) 1432 foreign_endian = 1; 1433 else 1434 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 1435 } 1436 1437 /* Initialize a new decoder context. */ 1438 if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL) 1439 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM); 1440 memset (dctx, 0, sizeof (sframe_decoder_ctx)); 1441 1442 if (foreign_endian) 1443 { 1444 /* Allocate a new buffer and initialize it. */ 1445 tempbuf = (char *) malloc (sf_size * sizeof (char)); 1446 if (tempbuf == NULL) 1447 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM); 1448 memcpy (tempbuf, sf_buf, sf_size); 1449 1450 /* Flip the header first. */ 1451 if (flip_header (tempbuf, sfp->sfp_version)) 1452 { 1453 sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 1454 goto decode_fail_free; 1455 } 1456 /* Flip the rest of the SFrame section data buffer. */ 1457 if (flip_sframe (tempbuf, sf_size, 0)) 1458 { 1459 sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 1460 goto decode_fail_free; 1461 } 1462 1463 frame_buf = tempbuf; 1464 /* This buffer is malloc'd when endian flipping the contents of the input 1465 buffer are needed. Keep a reference to it so it can be free'd up 1466 later in sframe_decoder_free (). */ 1467 dctx->sfd_buf = tempbuf; 1468 } 1469 else 1470 frame_buf = (char *)sf_buf; 1471 1472 /* Handle the SFrame header. */ 1473 dctx->sfd_header = *(sframe_header *) frame_buf; 1474 /* Validate the contents of SFrame header. */ 1475 dhp = &dctx->sfd_header; 1476 if (!sframe_header_sanity_check_p (dhp)) 1477 { 1478 sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 1479 goto decode_fail_free; 1480 } 1481 hdrsz = sframe_get_hdr_size (dhp); 1482 frame_buf += hdrsz; 1483 1484 /* Handle the SFrame Function Descriptor Entry section. */ 1485 if (sframe_fde_tbl_alloc (&dctx->sfd_funcdesc, dhp->sfh_num_fdes)) 1486 { 1487 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM); 1488 goto decode_fail_free; 1489 } 1490 1491 /* SFrame FDEs are at an offset of sfh_fdeoff from SFrame header end. */ 1492 if (sframe_fde_tbl_init (dctx->sfd_funcdesc, frame_buf + dhp->sfh_fdeoff, 1493 frame_buf + dhp->sfh_freoff, 1494 &fidx_size, dhp->sfh_num_fdes, sfp->sfp_version)) 1495 { 1496 sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 1497 goto decode_fail_free; 1498 } 1499 1500 debug_printf ("%zu total fidx size\n", fidx_size); 1501 1502 /* Handle the SFrame Frame Row Entry section. */ 1503 dctx->sfd_fres = (char *) malloc (dhp->sfh_fre_len); 1504 if (dctx->sfd_fres == NULL) 1505 { 1506 sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM); 1507 goto decode_fail_free; 1508 } 1509 /* SFrame FREs are at an offset of sfh_freoff from SFrame header end. */ 1510 memcpy (dctx->sfd_fres, frame_buf + dhp->sfh_freoff, dhp->sfh_fre_len); 1511 1512 fre_bytes = dhp->sfh_fre_len; 1513 dctx->sfd_fre_nbytes = fre_bytes; 1514 1515 debug_printf ("%u total fre bytes\n", fre_bytes); 1516 1517 return dctx; 1518 1519 decode_fail_free: 1520 if (foreign_endian && tempbuf != NULL) 1521 free (tempbuf); 1522 sframe_decoder_free (&dctx); 1523 dctx = NULL; 1524 return dctx; 1525 } 1526 1527 /* Get the size of the SFrame header from the decoder context CTX. */ 1528 1529 unsigned int 1530 sframe_decoder_get_hdr_size (const sframe_decoder_ctx *ctx) 1531 { 1532 const sframe_header *dhp = sframe_decoder_get_header (ctx); 1533 return sframe_get_hdr_size (dhp); 1534 } 1535 1536 /* Get the SFrame's abi/arch info given the decoder context DCTX. */ 1537 1538 uint8_t 1539 sframe_decoder_get_abi_arch (const sframe_decoder_ctx *dctx) 1540 { 1541 const sframe_header *dhp = sframe_decoder_get_header (dctx); 1542 return dhp->sfh_abi_arch; 1543 } 1544 1545 /* Get the format version from the SFrame decoder context DCTX. */ 1546 1547 uint8_t 1548 sframe_decoder_get_version (const sframe_decoder_ctx *dctx) 1549 { 1550 const sframe_header *dhp = sframe_decoder_get_header (dctx); 1551 return dhp->sfh_preamble.sfp_version; 1552 } 1553 1554 /* Get the section flags from the SFrame decoder context DCTX. */ 1555 1556 uint8_t 1557 sframe_decoder_get_flags (const sframe_decoder_ctx *dctx) 1558 { 1559 const sframe_header *dhp = sframe_decoder_get_header (dctx); 1560 return dhp->sfh_preamble.sfp_flags; 1561 } 1562 1563 /* Get the SFrame's fixed FP offset given the decoder context CTX. */ 1564 int8_t 1565 sframe_decoder_get_fixed_fp_offset (const sframe_decoder_ctx *ctx) 1566 { 1567 const sframe_header *dhp = sframe_decoder_get_header (ctx); 1568 return dhp->sfh_cfa_fixed_fp_offset; 1569 } 1570 1571 /* Get the SFrame's fixed RA offset given the decoder context CTX. */ 1572 int8_t 1573 sframe_decoder_get_fixed_ra_offset (const sframe_decoder_ctx *ctx) 1574 { 1575 const sframe_header *dhp = sframe_decoder_get_header (ctx); 1576 return dhp->sfh_cfa_fixed_ra_offset; 1577 } 1578 1579 /* Get the offset of the sfde_func_start_address field (from the start of the 1580 on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the decoder 1581 context DCTX. 1582 1583 If FUNC_IDX is more than the number of SFrame FDEs in the section, sets 1584 error code in ERRP, but returns the (hypothetical) offset. This is useful 1585 for the linker when arranging input FDEs into the output section to be 1586 emitted. */ 1587 1588 uint32_t 1589 sframe_decoder_get_offsetof_fde_start_addr (const sframe_decoder_ctx *dctx, 1590 uint32_t func_idx, int *errp) 1591 { 1592 if (func_idx >= sframe_decoder_get_num_fidx (dctx)) 1593 sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND); 1594 else if (errp) 1595 *errp = 0; 1596 1597 if (sframe_decoder_get_version (dctx) == SFRAME_VERSION_3) 1598 return (sframe_decoder_get_hdr_size (dctx) 1599 + func_idx * sizeof (sframe_func_desc_idx_v3) 1600 + offsetof (sframe_func_desc_idx_v3, sfdi_func_start_offset)); 1601 else if (sframe_decoder_get_version (dctx) == SFRAME_VERSION_2) 1602 return (sframe_decoder_get_hdr_size (dctx) 1603 + func_idx * sizeof (sframe_func_desc_entry_v2) 1604 + offsetof (sframe_func_desc_entry_v2, sfde_func_start_address)); 1605 else 1606 sframe_ret_set_errno (errp, SFRAME_ERR_INVAL); 1607 1608 return 0; 1609 } 1610 1611 /* Find the function descriptor entry starting which contains the specified 1612 address ADDR. */ 1613 1614 static sframe_func_desc_entry_int * 1615 sframe_get_funcdesc_with_addr_internal (const sframe_decoder_ctx *ctx, 1616 int64_t addr, int *errp, 1617 uint32_t *func_idx) 1618 { 1619 sframe_func_desc_entry_int *fdp; 1620 int low, high; 1621 1622 if (ctx == NULL) 1623 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL); 1624 1625 const sframe_header *dhp = sframe_decoder_get_header (ctx); 1626 1627 if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL) 1628 return sframe_ret_set_errno (errp, SFRAME_ERR_DCTX_INVAL); 1629 /* If the FDE sub-section is not sorted on PCs, skip the lookup because 1630 binary search cannot be used. */ 1631 if ((sframe_decoder_get_flags (ctx) & SFRAME_F_FDE_SORTED) == 0) 1632 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTSORTED); 1633 1634 /* Do the binary search. */ 1635 fdp = (sframe_func_desc_entry_int *) ctx->sfd_funcdesc->entry; 1636 low = 0; 1637 high = dhp->sfh_num_fdes - 1; 1638 while (low <= high) 1639 { 1640 int mid = low + (high - low) / 2; 1641 1642 /* Given func_start_addr <= addr, 1643 addr - func_start_addr must be positive. */ 1644 if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) <= addr 1645 && ((uint32_t)(addr - sframe_decoder_get_secrel_func_start_addr (ctx, 1646 mid)) 1647 < fdp[mid].func_size)) 1648 { 1649 *func_idx = mid; 1650 return fdp + mid; 1651 } 1652 1653 if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) < addr) 1654 low = mid + 1; 1655 else 1656 high = mid - 1; 1657 } 1658 1659 return sframe_ret_set_errno (errp, SFRAME_ERR_FDE_NOTFOUND); 1660 } 1661 1662 /* Get the end IP offset for the FRE at index i in the FDEP. The buffer FRES 1663 is the starting location for the FRE. */ 1664 1665 static uint32_t 1666 sframe_fre_get_end_ip_offset (sframe_func_desc_entry_int *fdep, unsigned int i, 1667 const char *fres) 1668 { 1669 uint32_t end_ip_offset; 1670 uint32_t fre_type; 1671 1672 fre_type = sframe_get_fre_type (fdep); 1673 1674 /* Get the start address of the next FRE in sequence. */ 1675 if (i < fdep->func_num_fres - 1) 1676 { 1677 sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type); 1678 end_ip_offset -= 1; 1679 } 1680 else 1681 /* The end IP offset for the FRE needs to be deduced from the function 1682 size. */ 1683 end_ip_offset = fdep->func_size - 1; 1684 1685 return end_ip_offset; 1686 } 1687 1688 /* Find the SFrame Row Entry which contains the PC. Returns 1689 SFRAME_ERR if failure. */ 1690 1691 int 1692 sframe_find_fre (const sframe_decoder_ctx *ctx, int64_t pc, 1693 sframe_frame_row_entry *frep) 1694 { 1695 sframe_frame_row_entry cur_fre; 1696 sframe_func_desc_entry_int *fdep; 1697 uint32_t func_idx; 1698 uint32_t fre_type, i; 1699 int64_t func_start_pc_offset; 1700 uint32_t start_ip_offset, end_ip_offset; 1701 const char *fres; 1702 size_t size = 0; 1703 int err = 0; 1704 1705 if ((ctx == NULL) || (frep == NULL)) 1706 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 1707 1708 uint8_t ver = sframe_decoder_get_version (ctx); 1709 /* Find the FDE which contains the PC, then scan its fre entries. */ 1710 fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err, &func_idx); 1711 if (fdep == NULL || ctx->sfd_fres == NULL) 1712 return sframe_set_errno (&err, SFRAME_ERR_DCTX_INVAL); 1713 1714 fre_type = sframe_get_fre_type (fdep); 1715 1716 fres = ctx->sfd_fres + fdep->func_start_fre_off; 1717 if (ver == SFRAME_VERSION_3) 1718 fres += sizeof (sframe_func_desc_attr_v3); 1719 func_start_pc_offset = sframe_decoder_get_secrel_func_start_addr (ctx, 1720 func_idx); 1721 1722 for (i = 0; i < fdep->func_num_fres; i++) 1723 { 1724 err = sframe_decode_fre (fres, &cur_fre, fre_type, &size); 1725 if (err) 1726 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); 1727 1728 start_ip_offset = cur_fre.fre_start_addr; 1729 end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size); 1730 1731 /* Stop search if FRE's start_ip is greater than pc. Given 1732 func_start_addr <= pc, pc - func_start_addr must be positive. */ 1733 if (start_ip_offset > (uint32_t)(pc - func_start_pc_offset)) 1734 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); 1735 1736 if (sframe_fre_check_range_p (ctx, func_idx, start_ip_offset, 1737 end_ip_offset, pc)) 1738 { 1739 sframe_frame_row_entry_copy (frep, &cur_fre); 1740 return 0; 1741 } 1742 fres += size; 1743 } 1744 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL); 1745 } 1746 1747 /* Return the number of function descriptor entries in the SFrame decoder 1748 DCTX. */ 1749 1750 uint32_t 1751 sframe_decoder_get_num_fidx (const sframe_decoder_ctx *ctx) 1752 { 1753 uint32_t num_fdes = 0; 1754 const sframe_header *dhp = sframe_decoder_get_header (ctx); 1755 if (dhp) 1756 num_fdes = dhp->sfh_num_fdes; 1757 return num_fdes; 1758 } 1759 1760 int 1761 sframe_decoder_get_funcdesc_v2 (const sframe_decoder_ctx *dctx, 1762 unsigned int i, 1763 uint32_t *num_fres, 1764 uint32_t *func_size, 1765 int32_t *func_start_address, 1766 unsigned char *func_info, 1767 uint8_t *rep_block_size) 1768 { 1769 sframe_func_desc_entry_int *fdp; 1770 int err = 0; 1771 1772 if (dctx == NULL || func_start_address == NULL 1773 || num_fres == NULL || func_size == NULL 1774 || sframe_decoder_get_version (dctx) == SFRAME_VERSION_1) 1775 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 1776 1777 fdp = sframe_decoder_get_funcdesc_at_index (dctx, i); 1778 1779 if (fdp == NULL) 1780 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND); 1781 1782 *num_fres = fdp->func_num_fres; 1783 *func_start_address = (int32_t) fdp->func_start_pc_offset; 1784 *func_size = fdp->func_size; 1785 *func_info = fdp->func_info; 1786 *rep_block_size = fdp->func_rep_size; 1787 1788 return 0; 1789 } 1790 1791 /* Get the data (NUM_FRES, FUNC_SIZE, START_PC_OFFSET, FUNC_INFO, 1792 REP_BLOCK_SIZE) from the SFrame function descriptor entry at the I'th index 1793 in the decoder object DCTX. Return SFRAME_ERR on failure. */ 1794 1795 int 1796 sframe_decoder_get_funcdesc_v3 (const sframe_decoder_ctx *dctx, 1797 unsigned int i, 1798 uint32_t *num_fres, 1799 uint32_t *func_size, 1800 int64_t *start_pc_offset, 1801 unsigned char *func_info, 1802 unsigned char *func_info2, 1803 uint8_t *rep_block_size) 1804 { 1805 int err = 0; 1806 if (dctx == NULL || sframe_decoder_get_version (dctx) != SFRAME_VERSION_3) 1807 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 1808 1809 sframe_func_desc_entry_int *fdp 1810 = sframe_decoder_get_funcdesc_at_index (dctx, i); 1811 if (fdp == NULL) 1812 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND); 1813 1814 if (num_fres) 1815 *num_fres = fdp->func_num_fres; 1816 if (start_pc_offset) 1817 *start_pc_offset = fdp->func_start_pc_offset; 1818 if (func_size) 1819 *func_size = fdp->func_size; 1820 if (func_info) 1821 *func_info = fdp->func_info; 1822 if (func_info2) 1823 *func_info2 = fdp->func_info2; 1824 if (rep_block_size) 1825 *rep_block_size = fdp->func_rep_size; 1826 1827 return 0; 1828 } 1829 1830 /* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function 1831 descriptor entry in the SFrame decoder CTX. Returns error code as 1832 applicable. */ 1833 1834 int 1835 sframe_decoder_get_fre (const sframe_decoder_ctx *ctx, 1836 unsigned int func_idx, 1837 unsigned int fre_idx, 1838 sframe_frame_row_entry *fre) 1839 { 1840 sframe_func_desc_entry_int *fdep; 1841 sframe_frame_row_entry ifre; 1842 const char *fres; 1843 uint32_t i; 1844 uint32_t fre_type; 1845 size_t esz = 0; 1846 int err = 0; 1847 1848 if (ctx == NULL || fre == NULL) 1849 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 1850 1851 uint8_t ver = sframe_decoder_get_version (ctx); 1852 1853 /* Get function descriptor entry at index func_idx. */ 1854 fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx); 1855 if (fdep == NULL) 1856 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND); 1857 1858 fre_type = sframe_get_fre_type (fdep); 1859 /* Now scan the FRE entries. */ 1860 fres = ctx->sfd_fres + fdep->func_start_fre_off; 1861 if (ver == SFRAME_VERSION_3) 1862 fres += sizeof (sframe_func_desc_attr_v3); 1863 1864 for (i = 0; i < fdep->func_num_fres; i++) 1865 { 1866 /* Decode the FRE at the current position. Return it if valid. */ 1867 err = sframe_decode_fre (fres, &ifre, fre_type, &esz); 1868 if (i == fre_idx) 1869 { 1870 if (!sframe_fre_sanity_check_p (&ifre)) 1871 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); 1872 1873 /* Although a stricter sanity check on fre_start_addr like: 1874 if (fdep->func_size) 1875 sframe_assert (frep->fre_start_addr < fdep->func_size); 1876 is more suitable, some code has been seen to not abide by it. See 1877 PR libsframe/33131. */ 1878 sframe_assert (ifre.fre_start_addr <= fdep->func_size); 1879 1880 sframe_frame_row_entry_copy (fre, &ifre); 1881 1882 return 0; 1883 } 1884 /* Next FRE. */ 1885 fres += esz; 1886 } 1887 1888 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND); 1889 } 1890 1891 /* Get the SFrame FRE data of the function at FUNC_IDX'th function index entry 1892 in the SFrame decoder DCTX. The reference to the buffer is returned in 1893 FRES_BUF with FRES_BUF_SIZE indicating the size of the buffer. The number 1894 of FREs in the buffer are NUM_FRES. In SFrame V3, this buffer also contains 1895 the FDE attr data before the actual SFrame FREs. Returns SFRAME_ERR in case 1896 of error. */ 1897 1898 int 1899 sframe_decoder_get_fres_buf (const sframe_decoder_ctx *dctx, 1900 const uint32_t func_idx, 1901 char **fres_buf, 1902 size_t *fres_buf_size, 1903 uint32_t *num_fres) 1904 { 1905 sframe_func_desc_entry_int *fdep; 1906 uint32_t i = 0; 1907 uint32_t fre_type; 1908 size_t esz; 1909 int err = 0; 1910 1911 if (dctx == NULL || fres_buf == NULL) 1912 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 1913 1914 /* Get function descriptor entry at index func_idx. */ 1915 fdep = sframe_decoder_get_funcdesc_at_index (dctx, func_idx); 1916 *num_fres = fdep->func_num_fres; 1917 1918 if (fdep == NULL) 1919 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND); 1920 1921 fre_type = sframe_get_fre_type (fdep); 1922 /* Update the pointer to (and total size of) the FRE entries. */ 1923 *fres_buf = dctx->sfd_fres + fdep->func_start_fre_off; 1924 const char *tmp_buf = *fres_buf + sizeof (sframe_func_desc_attr_v3); 1925 *fres_buf_size = sizeof (sframe_func_desc_attr_v3); 1926 while (i < *num_fres) 1927 { 1928 /* Avoid cost of full decoding at this time. */ 1929 esz = sframe_buf_fre_entry_size (tmp_buf, fre_type); 1930 tmp_buf += esz; 1931 *fres_buf_size += esz; 1932 i++; 1933 } 1934 1935 return 0; 1936 } 1937 1938 1939 /* SFrame Encoder. */ 1940 1941 /* Get a reference to the SFrame header, given the encoder context ECTX. */ 1942 1943 static sframe_header * 1944 sframe_encoder_get_header (sframe_encoder_ctx *ectx) 1945 { 1946 sframe_header *hp = NULL; 1947 if (ectx) 1948 hp = &ectx->sfe_header; 1949 return hp; 1950 } 1951 1952 static sframe_func_desc_entry_int * 1953 sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *ectx, 1954 uint32_t func_idx) 1955 { 1956 sframe_func_desc_entry_int *fde = NULL; 1957 if (func_idx < sframe_encoder_get_num_fidx (ectx)) 1958 { 1959 sf_fde_tbl *func_tbl = ectx->sfe_funcdesc; 1960 fde = func_tbl->entry + func_idx; 1961 } 1962 return fde; 1963 } 1964 1965 /* Create an encoder context with the given SFrame format version VER, FLAGS 1966 and ABI information. Uses the ABI specific FIXED_FP_OFFSET and 1967 FIXED_RA_OFFSET values as provided. Sets errp if failure. */ 1968 1969 sframe_encoder_ctx * 1970 sframe_encode (uint8_t ver, uint8_t flags, uint8_t abi_arch, 1971 int8_t fixed_fp_offset, int8_t fixed_ra_offset, int *errp) 1972 { 1973 sframe_header *hp; 1974 sframe_encoder_ctx *ectx; 1975 1976 if (ver != SFRAME_VERSION) 1977 return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL); 1978 1979 if ((ectx = malloc (sizeof (sframe_encoder_ctx))) == NULL) 1980 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM); 1981 1982 memset (ectx, 0, sizeof (sframe_encoder_ctx)); 1983 1984 /* Get the SFrame header and update it. */ 1985 hp = sframe_encoder_get_header (ectx); 1986 hp->sfh_preamble.sfp_version = ver; 1987 hp->sfh_preamble.sfp_magic = SFRAME_MAGIC; 1988 hp->sfh_preamble.sfp_flags = flags; 1989 1990 /* Implementation in the SFrame encoder APIs, e.g., 1991 sframe_encoder_write_sframe assume flag SFRAME_F_FDE_FUNC_START_PCREL 1992 set. */ 1993 if (!(flags & SFRAME_F_FDE_FUNC_START_PCREL)) 1994 return sframe_ret_set_errno (errp, SFRAME_ERR_ECTX_INVAL); 1995 1996 hp->sfh_abi_arch = abi_arch; 1997 hp->sfh_cfa_fixed_fp_offset = fixed_fp_offset; 1998 hp->sfh_cfa_fixed_ra_offset = fixed_ra_offset; 1999 2000 return ectx; 2001 } 2002 2003 /* Free the encoder context ECTXP. */ 2004 2005 void 2006 sframe_encoder_free (sframe_encoder_ctx **ectxp) 2007 { 2008 if (ectxp != NULL) 2009 { 2010 sframe_encoder_ctx *ectx = *ectxp; 2011 if (ectx == NULL) 2012 return; 2013 2014 if (ectx->sfe_funcdesc != NULL) 2015 { 2016 free (ectx->sfe_funcdesc); 2017 ectx->sfe_funcdesc = NULL; 2018 } 2019 if (ectx->sfe_fres != NULL) 2020 { 2021 free (ectx->sfe_fres); 2022 ectx->sfe_fres = NULL; 2023 } 2024 if (ectx->sfe_data != NULL) 2025 { 2026 free (ectx->sfe_data); 2027 ectx->sfe_data = NULL; 2028 } 2029 2030 free (*ectxp); 2031 *ectxp = NULL; 2032 } 2033 } 2034 2035 /* Get the size of the SFrame header from the encoder context ECTX. */ 2036 2037 unsigned int 2038 sframe_encoder_get_hdr_size (sframe_encoder_ctx *ectx) 2039 { 2040 const sframe_header *ehp = sframe_encoder_get_header (ectx); 2041 return sframe_get_hdr_size (ehp); 2042 } 2043 2044 /* Get the SFrame abi/arch info from the encoder context ECTX. */ 2045 2046 uint8_t 2047 sframe_encoder_get_abi_arch (sframe_encoder_ctx *ectx) 2048 { 2049 uint8_t abi_arch = 0; 2050 const sframe_header *ehp = sframe_encoder_get_header (ectx); 2051 if (ehp) 2052 abi_arch = ehp->sfh_abi_arch; 2053 return abi_arch; 2054 } 2055 2056 /* Get the SFrame format version from the encoder context ECTX. */ 2057 2058 uint8_t 2059 sframe_encoder_get_version (sframe_encoder_ctx *ectx) 2060 { 2061 const sframe_header *ehp = sframe_encoder_get_header (ectx); 2062 return ehp->sfh_preamble.sfp_version; 2063 } 2064 2065 /* Get the SFrame flags from the encoder context ECTX. */ 2066 2067 uint8_t 2068 sframe_encoder_get_flags (sframe_encoder_ctx *ectx) 2069 { 2070 const sframe_header *ehp = sframe_encoder_get_header (ectx); 2071 return ehp->sfh_preamble.sfp_flags; 2072 } 2073 2074 /* Return the number of SFrame function descriptor entries in the encoder 2075 context ECTX. */ 2076 2077 uint32_t 2078 sframe_encoder_get_num_fidx (sframe_encoder_ctx *ectx) 2079 { 2080 uint32_t num_fdes = 0; 2081 const sframe_header *ehp = sframe_encoder_get_header (ectx); 2082 if (ehp) 2083 num_fdes = ehp->sfh_num_fdes; 2084 return num_fdes; 2085 } 2086 2087 /* Get the offset of the sfde_func_start_address field (from the start of the 2088 on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the encoder 2089 context ECTX. 2090 2091 If FUNC_IDX is more than the number of SFrame FDEs in the section, sets 2092 error code in ERRP, but returns the (hypothetical) offset. This is useful 2093 for the linker when arranging input FDEs into the output section to be 2094 emitted. */ 2095 2096 uint32_t 2097 sframe_encoder_get_offsetof_fde_start_addr (sframe_encoder_ctx *ectx, 2098 uint32_t func_idx, int *errp) 2099 { 2100 if (func_idx >= sframe_encoder_get_num_fidx (ectx)) 2101 sframe_ret_set_errno (errp, SFRAME_ERR_FDE_INVAL); 2102 else if (errp) 2103 *errp = 0; 2104 2105 return (sframe_encoder_get_hdr_size (ectx) 2106 + func_idx * sizeof (sframe_func_desc_idx_v3) 2107 + offsetof (sframe_func_desc_idx_v3, sfdi_func_start_offset)); 2108 } 2109 2110 /* Add an SFrame FRE to function at FUNC_IDX'th function descriptor entry in 2111 the encoder context ECTX. */ 2112 2113 int 2114 sframe_encoder_add_fre (sframe_encoder_ctx *ectx, 2115 unsigned int func_idx, 2116 sframe_frame_row_entry *frep) 2117 { 2118 sframe_header *ehp; 2119 sframe_func_desc_entry_int *fdep; 2120 sframe_frame_row_entry *ectx_frep; 2121 size_t datawords_sz, esz; 2122 uint32_t fre_type; 2123 int err = 0; 2124 2125 if (ectx == NULL || frep == NULL) 2126 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 2127 if (!sframe_fre_sanity_check_p (frep)) 2128 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); 2129 2130 /* Use func_idx to gather the function descriptor entry. */ 2131 fdep = sframe_encoder_get_funcdesc_at_index (ectx, func_idx); 2132 2133 if (fdep == NULL) 2134 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND); 2135 2136 fre_type = sframe_get_fre_type (fdep); 2137 sf_fre_tbl *fre_tbl = ectx->sfe_fres; 2138 2139 if (fre_tbl == NULL || fre_tbl->count == fre_tbl->alloced) 2140 { 2141 sf_fre_tbl *tmp = sframe_grow_fre_tbl (fre_tbl, 1, &err); 2142 if (err) 2143 { 2144 sframe_set_errno (&err, SFRAME_ERR_NOMEM); 2145 goto bad; 2146 } 2147 fre_tbl = tmp; 2148 } 2149 2150 ectx_frep = &fre_tbl->entry[fre_tbl->count]; 2151 ectx_frep->fre_start_addr 2152 = frep->fre_start_addr; 2153 ectx_frep->fre_info = frep->fre_info; 2154 2155 /* Although a stricter sanity check on fre_start_addr like: 2156 if (fdep->func_size) 2157 sframe_assert (frep->fre_start_addr < fdep->func_size); 2158 is more suitable, some code has been seen to not abide by it. See PR 2159 libsframe/33131. */ 2160 sframe_assert (frep->fre_start_addr <= fdep->func_size); 2161 2162 /* frep has already been sanity check'd. Get offsets size. */ 2163 datawords_sz = sframe_fre_datawords_bytes_size (frep->fre_info); 2164 memcpy (&ectx_frep->fre_datawords, &frep->fre_datawords, datawords_sz); 2165 2166 esz = sframe_fre_entry_size (frep, fre_type); 2167 fre_tbl->count++; 2168 2169 ectx->sfe_fres = fre_tbl; 2170 ectx->sfe_fre_nbytes += esz; 2171 2172 if (!fdep->func_num_fres) 2173 ectx->sfe_fre_nbytes += sizeof (sframe_func_desc_attr_v3); 2174 2175 ehp = sframe_encoder_get_header (ectx); 2176 ehp->sfh_num_fres = fre_tbl->count; 2177 2178 /* Update the value of the number of FREs for the function. */ 2179 fdep->func_num_fres++; 2180 2181 return 0; 2182 2183 bad: 2184 if (fre_tbl != NULL) 2185 free (fre_tbl); 2186 ectx->sfe_fres = NULL; 2187 ectx->sfe_fre_nbytes = 0; 2188 return -1; 2189 } 2190 2191 /* Add SFrame FRE data given in the buffer FRES_BUF of size FRES_BUF_SIZE (for 2192 function at index FUNC_IDX) to the encoder context ECTX. The number of FREs 2193 in the buffer are NUM_FRES. Returns SFRAME_ERR if failure. */ 2194 2195 int 2196 sframe_encoder_add_fres_buf (sframe_encoder_ctx *ectx, 2197 unsigned int func_idx, 2198 uint32_t num_fres, 2199 const char *fres_buf, 2200 size_t fres_buf_size) 2201 { 2202 sframe_frame_row_entry *ectx_frep; 2203 size_t esz = 0; 2204 2205 int err = 0; 2206 if (ectx == NULL || ((fres_buf == NULL) != (fres_buf_size == 0))) 2207 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 2208 2209 /* Use func_idx to gather the function descriptor entry. */ 2210 sframe_func_desc_entry_int *fdep 2211 = sframe_encoder_get_funcdesc_at_index (ectx, func_idx); 2212 if (fdep == NULL) 2213 return sframe_set_errno (&err, SFRAME_ERR_FDE_NOTFOUND); 2214 2215 sf_fre_tbl *fre_tbl = ectx->sfe_fres; 2216 if (fre_tbl == NULL || fre_tbl->count + num_fres >= fre_tbl->alloced) 2217 { 2218 sf_fre_tbl *tmp = sframe_grow_fre_tbl (fre_tbl, num_fres, &err); 2219 if (err) 2220 { 2221 sframe_set_errno (&err, SFRAME_ERR_NOMEM); 2222 goto bad; /* OOM. */ 2223 } 2224 fre_tbl = tmp; 2225 } 2226 2227 /* Update the SFrame func attr values. */ 2228 fdep->func_num_fres = num_fres; 2229 const char *fres = fres_buf + sizeof (uint16_t); 2230 fdep->func_info = *(uint8_t *)fres; 2231 fres += sizeof (uint8_t); 2232 fdep->func_info2 = *(uint8_t *)fres; 2233 fres += sizeof (uint8_t); 2234 fdep->func_rep_size = *(uint8_t *)fres; 2235 fres += sizeof (uint8_t); 2236 2237 uint32_t fre_type = sframe_get_fre_type (fdep); 2238 uint32_t remaining = num_fres; 2239 size_t buf_size = sizeof (sframe_func_desc_attr_v3); 2240 while (remaining) 2241 { 2242 ectx_frep = &fre_tbl->entry[fre_tbl->count]; 2243 /* Copy the SFrame FRE data over to the encoder object's fre_tbl. */ 2244 sframe_decode_fre (fres, ectx_frep, fre_type, &esz); 2245 2246 if (!sframe_fre_sanity_check_p (ectx_frep)) 2247 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); 2248 2249 /* Although a stricter sanity check on fre_start_addr like: 2250 if (fdep->func_size) 2251 sframe_assert (frep->fre_start_addr < fdep->func_size); 2252 is more suitable, some code has been seen to not abide by it. See PR 2253 libsframe/33131. */ 2254 sframe_assert (ectx_frep->fre_start_addr <= fdep->func_size); 2255 2256 fre_tbl->count++; 2257 fres += esz; 2258 buf_size += esz; 2259 remaining--; 2260 } 2261 2262 sframe_assert (fres_buf_size == buf_size); 2263 ectx->sfe_fres = fre_tbl; 2264 ectx->sfe_fre_nbytes += buf_size; 2265 2266 sframe_header *ehp = sframe_encoder_get_header (ectx); 2267 ehp->sfh_num_fres = fre_tbl->count; 2268 2269 return 0; 2270 2271 bad: 2272 if (fre_tbl != NULL) 2273 free (fre_tbl); 2274 ectx->sfe_fres = NULL; 2275 ectx->sfe_fre_nbytes = 0; 2276 return -1; 2277 } 2278 2279 /* Add a new SFrame function descriptor entry with START_ADDR, FUNC_SIZE and 2280 FUNC_INFO to the encoder context ECTX. Caller must make sure that ECTX 2281 exists. */ 2282 2283 static int 2284 sframe_encoder_add_funcdesc_internal (sframe_encoder_ctx *ectx, 2285 int64_t start_addr, 2286 uint32_t func_size) 2287 { 2288 sframe_header *ehp; 2289 sf_fde_tbl *fd_info; 2290 size_t fd_tbl_sz; 2291 int err = 0; 2292 2293 fd_info = ectx->sfe_funcdesc; 2294 ehp = sframe_encoder_get_header (ectx); 2295 2296 if (fd_info == NULL) 2297 { 2298 fd_tbl_sz = (sizeof (sf_fde_tbl) 2299 + (number_of_entries * sizeof (sframe_func_desc_entry_int))); 2300 fd_info = malloc (fd_tbl_sz); 2301 if (fd_info == NULL) 2302 { 2303 sframe_set_errno (&err, SFRAME_ERR_NOMEM); 2304 goto bad; /* OOM. */ 2305 } 2306 memset (fd_info, 0, fd_tbl_sz); 2307 fd_info->alloced = number_of_entries; 2308 } 2309 else if (fd_info->count == fd_info->alloced) 2310 { 2311 fd_tbl_sz = (sizeof (sf_fde_tbl) 2312 + ((fd_info->alloced + number_of_entries) 2313 * sizeof (sframe_func_desc_entry_int))); 2314 sf_fde_tbl *tmp = realloc (fd_info, fd_tbl_sz); 2315 if (tmp == NULL) 2316 { 2317 sframe_set_errno (&err, SFRAME_ERR_NOMEM); 2318 goto bad; /* OOM. */ 2319 } 2320 fd_info = tmp; 2321 2322 memset (&fd_info->entry[fd_info->alloced], 0, 2323 number_of_entries * sizeof (sframe_func_desc_entry_int)); 2324 fd_info->alloced += number_of_entries; 2325 } 2326 2327 fd_info->entry[fd_info->count].func_start_pc_offset = start_addr; 2328 /* Num FREs is updated as FREs are added for the function later via 2329 sframe_encoder_add_fre. */ 2330 fd_info->entry[fd_info->count].func_size = func_size; 2331 fd_info->entry[fd_info->count].func_start_fre_off = ectx->sfe_fre_nbytes; 2332 #if 0 2333 // Linker optimization test code cleanup later ibhagat TODO FIXME 2334 uint32_t fre_type = sframe_calc_fre_type (func_size); 2335 2336 fd_info->entry[fd_info->count].sfde_func_info 2337 = sframe_fde_func_info (fre_type); 2338 #endif 2339 fd_info->count++; 2340 ectx->sfe_funcdesc = fd_info; 2341 ehp->sfh_num_fdes++; 2342 return 0; 2343 2344 bad: 2345 if (fd_info != NULL) 2346 free (fd_info); 2347 ectx->sfe_funcdesc = NULL; 2348 ehp->sfh_num_fdes = 0; 2349 return err; 2350 } 2351 2352 /* Add a new SFrame function descriptor entry with START_PC_OFFSET and 2353 FUNC_SIZE to the encoder context ECTX. */ 2354 2355 int 2356 sframe_encoder_add_funcdesc (sframe_encoder_ctx *ectx, int64_t start_pc_offset, 2357 uint32_t func_size) 2358 { 2359 int err = 0; 2360 if (ectx == NULL || sframe_encoder_get_version (ectx) == SFRAME_VERSION_1) 2361 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 2362 2363 err = sframe_encoder_add_funcdesc_internal (ectx, start_pc_offset, func_size); 2364 if (err) 2365 return err; 2366 2367 return 0; 2368 } 2369 2370 /* Add a new SFrame function descriptor entry with START_ADDR, FUNC_SIZE, 2371 FUNC_INFO and REP_BLOCK_SIZE to the encoder context ECTX. This API is valid 2372 only for SFrame format version 2. */ 2373 2374 int 2375 sframe_encoder_add_funcdesc_v2 (sframe_encoder_ctx *ectx, 2376 int32_t start_addr, 2377 uint32_t func_size, 2378 unsigned char func_info, 2379 uint8_t rep_block_size, 2380 uint32_t num_fres ATTRIBUTE_UNUSED) 2381 { 2382 int err = 0; 2383 if (ectx == NULL || sframe_encoder_get_version (ectx) == SFRAME_VERSION_1) 2384 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 2385 2386 err = sframe_encoder_add_funcdesc_internal (ectx, start_addr, func_size); 2387 if (err) 2388 return err; 2389 2390 sf_fde_tbl *fd_info = ectx->sfe_funcdesc; 2391 fd_info->entry[fd_info->count-1].func_info = func_info; 2392 fd_info->entry[fd_info->count-1].func_rep_size = rep_block_size; 2393 2394 return 0; 2395 } 2396 2397 /* Add a new SFrame function descriptor entry with START_PC_OFFSET, FUNC_SIZE, 2398 FUNC_INFO, FUNC_INFO2 and REP_BLOCK_SIZE to the encoder context ECTX. 2399 Return error code on failure. */ 2400 2401 int 2402 sframe_encoder_add_funcdesc_v3 (sframe_encoder_ctx *ectx, 2403 int64_t start_pc_offset, 2404 uint32_t func_size, 2405 unsigned char func_info, 2406 unsigned char func_info2, 2407 uint8_t rep_block_size, 2408 uint32_t num_fres ATTRIBUTE_UNUSED) 2409 { 2410 int err = 0; 2411 if (ectx == NULL || sframe_encoder_get_version (ectx) != SFRAME_VERSION_3) 2412 { 2413 sframe_set_errno (&err, SFRAME_ERR_INVAL); 2414 return err; 2415 } 2416 2417 err = sframe_encoder_add_funcdesc_internal (ectx, start_pc_offset, 2418 func_size); 2419 if (err) 2420 return err; 2421 2422 sf_fde_tbl *fd_info = ectx->sfe_funcdesc; 2423 fd_info->entry[fd_info->count-1].func_info = func_info; 2424 fd_info->entry[fd_info->count-1].func_info2 = func_info2; 2425 fd_info->entry[fd_info->count-1].func_rep_size = rep_block_size; 2426 2427 return 0; 2428 } 2429 2430 static int 2431 sframe_sort_funcdesc (sframe_encoder_ctx *ectx) 2432 { 2433 sframe_header *ehp = sframe_encoder_get_header (ectx); 2434 2435 /* Sort and write out the FDE table. */ 2436 sf_fde_tbl *fd_info = ectx->sfe_funcdesc; 2437 if (fd_info) 2438 { 2439 /* The new encoding of sfde_func_start_address means the distances are 2440 not from the same anchor, so cannot be sorted directly. At the moment 2441 we adress this by manual value adjustments before and after sorting. 2442 FIXME - qsort_r may be more optimal. */ 2443 2444 for (unsigned int i = 0; i < fd_info->count; i++) 2445 fd_info->entry[i].func_start_pc_offset 2446 += sframe_encoder_get_offsetof_fde_start_addr (ectx, i, NULL); 2447 2448 qsort (fd_info->entry, fd_info->count, 2449 sizeof (sframe_func_desc_entry_int), fde_func); 2450 2451 for (unsigned int i = 0; i < fd_info->count; i++) 2452 fd_info->entry[i].func_start_pc_offset 2453 -= sframe_encoder_get_offsetof_fde_start_addr (ectx, i, NULL); 2454 2455 /* Update preamble's flags. */ 2456 ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED; 2457 } 2458 return 0; 2459 } 2460 2461 /* Write the SFrame FRE start address from the in-memory FRE_START_ADDR 2462 to the buffer CONTENTS (on-disk format), given the FRE_TYPE and 2463 FRE_START_ADDR_SZ. */ 2464 2465 static int 2466 sframe_encoder_write_fre_start_addr (char *contents, 2467 uint32_t fre_start_addr, 2468 uint32_t fre_type, 2469 size_t fre_start_addr_sz) 2470 { 2471 int err = 0; 2472 2473 if (fre_type == SFRAME_FRE_TYPE_ADDR1) 2474 { 2475 uint8_t uc = fre_start_addr; 2476 memcpy (contents, &uc, fre_start_addr_sz); 2477 } 2478 else if (fre_type == SFRAME_FRE_TYPE_ADDR2) 2479 { 2480 uint16_t ust = fre_start_addr; 2481 memcpy (contents, &ust, fre_start_addr_sz); 2482 } 2483 else if (fre_type == SFRAME_FRE_TYPE_ADDR4) 2484 { 2485 uint32_t uit = fre_start_addr; 2486 memcpy (contents, &uit, fre_start_addr_sz); 2487 } 2488 else 2489 return sframe_set_errno (&err, SFRAME_ERR_INVAL); 2490 2491 return 0; 2492 } 2493 2494 /* Write a frame row entry pointed to by FREP into the buffer CONTENTS. The 2495 size in bytes written out are updated in ESZ. 2496 2497 This function works closely with the SFrame binary format. 2498 2499 Returns SFRAME_ERR if failure. */ 2500 2501 static int 2502 sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep, 2503 uint32_t fre_type, size_t *esz) 2504 { 2505 size_t fre_sz; 2506 size_t fre_start_addr_sz; 2507 size_t fre_datawords_sz; 2508 int err = 0; 2509 2510 if (!sframe_fre_sanity_check_p (frep)) 2511 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); 2512 2513 fre_start_addr_sz = sframe_fre_start_addr_size (fre_type); 2514 fre_datawords_sz = sframe_fre_datawords_bytes_size (frep->fre_info); 2515 2516 /* The FRE start address must be encodable in the available number of 2517 bytes. */ 2518 uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz); 2519 sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask); 2520 2521 sframe_encoder_write_fre_start_addr (contents, frep->fre_start_addr, 2522 fre_type, fre_start_addr_sz); 2523 contents += fre_start_addr_sz; 2524 2525 memcpy (contents, &frep->fre_info, sizeof (frep->fre_info)); 2526 contents += sizeof (frep->fre_info); 2527 2528 memcpy (contents, frep->fre_datawords, fre_datawords_sz); 2529 contents+= fre_datawords_sz; 2530 2531 fre_sz = sframe_fre_entry_size (frep, fre_type); 2532 /* Sanity checking. */ 2533 sframe_assert ((fre_start_addr_sz 2534 + sizeof (frep->fre_info) 2535 + fre_datawords_sz) == fre_sz); 2536 2537 *esz = fre_sz; 2538 2539 return 0; 2540 } 2541 2542 /* Write an SFrame FDE Index element for SFrame V3 into the provided buffer at 2543 CONTENTS. Update FDE_WRITE_SIZE with the number of bytes written to the 2544 buffer. Return 0 on success, SFRAME_ERR otherwise. */ 2545 2546 static int 2547 sframe_encoder_write_fde_idx (const sframe_header *sfhp ATTRIBUTE_UNUSED, 2548 char *contents, 2549 const sframe_func_desc_entry_int *fde, 2550 size_t *fde_write_size) 2551 { 2552 sframe_func_desc_idx_v3 *fdep = (sframe_func_desc_idx_v3 *)contents; 2553 2554 fdep->sfdi_func_start_offset = fde->func_start_pc_offset; 2555 fdep->sfdi_func_size = fde->func_size; 2556 fdep->sfdi_func_start_fre_off = fde->func_start_fre_off; 2557 2558 *fde_write_size = sizeof (sframe_func_desc_idx_v3); 2559 2560 return 0; 2561 } 2562 2563 /* Write the SFrame FDE Attribute element for SFrame V3 into the provided 2564 buffer at CONTENTS. Return 0 on success, SFRAME_ERR otherwise. */ 2565 2566 static int 2567 sframe_encoder_write_fde_attr (char *contents, 2568 const sframe_func_desc_entry_int *fde) 2569 { 2570 sframe_func_desc_attr_v3 *fattr = (sframe_func_desc_attr_v3 *)contents; 2571 2572 /* Access to num_fres may be unaligned. */ 2573 uint16_t num_fres = (uint16_t)fde->func_num_fres; 2574 memcpy (fattr, &num_fres, sizeof (uint16_t)); 2575 2576 fattr->sfda_func_info = fde->func_info; 2577 fattr->sfda_func_info2 = fde->func_info2; 2578 fattr->sfda_func_rep_size = fde->func_rep_size; 2579 2580 return 0; 2581 } 2582 /* Serialize the core contents of the SFrame section and write out to the 2583 output buffer held in the encoder context ECTX. Sort the SFrame FDEs on 2584 start PC if SORT_FDE_P is true. Return SFRAME_ERR if failure. */ 2585 2586 static int 2587 sframe_encoder_write_sframe (sframe_encoder_ctx *ectx, bool sort_fde_p) 2588 { 2589 char *contents; 2590 size_t buf_size; 2591 size_t hdr_size; 2592 size_t fde_write_size, all_fdes_size; 2593 size_t fre_size; 2594 size_t esz = 0; 2595 sframe_header *ehp; 2596 sf_fde_tbl *fd_info; 2597 sf_fre_tbl *fr_info; 2598 uint32_t i, num_fdes; 2599 uint32_t j, num_fres; 2600 sframe_func_desc_entry_int *fdep; 2601 sframe_frame_row_entry *frep; 2602 2603 uint32_t fre_type; 2604 int err = 0; 2605 2606 contents = ectx->sfe_data; 2607 buf_size = ectx->sfe_data_size; 2608 num_fdes = sframe_encoder_get_num_fidx (ectx); 2609 all_fdes_size = num_fdes * sizeof (sframe_func_desc_idx_v3); 2610 ehp = sframe_encoder_get_header (ectx); 2611 hdr_size = sframe_get_hdr_size (ehp); 2612 2613 fd_info = ectx->sfe_funcdesc; 2614 fr_info = ectx->sfe_fres; 2615 2616 /* Sanity checks: 2617 - buffers must be malloc'd by the caller. */ 2618 if ((contents == NULL) || (buf_size < hdr_size)) 2619 return sframe_set_errno (&err, SFRAME_ERR_BUF_INVAL); 2620 if (ehp->sfh_num_fres > 0 && fr_info == NULL) 2621 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); 2622 2623 /* Write out the FRE table first. 2624 2625 Recall that read/write of FREs needs information from the corresponding 2626 FDE; the latter stores the information about the FRE type record used for 2627 the function. Also note that sorting of FDEs does NOT impact the order 2628 in which FREs are stored in the SFrame's FRE sub-section. This means 2629 that writing out FREs after sorting of FDEs will need some additional 2630 book-keeping. At this time, we can afford to avoid it by writing out 2631 the FREs first to the output buffer. */ 2632 fre_size = 0; 2633 uint32_t global = 0; 2634 uint32_t fre_index = 0; 2635 2636 contents += hdr_size + all_fdes_size; 2637 for (i = 0; i < num_fdes; i++) 2638 { 2639 fdep = &fd_info->entry[i]; 2640 fre_type = sframe_get_fre_type (fdep); 2641 num_fres = fdep->func_num_fres; 2642 2643 if (num_fres > 0 && fr_info == NULL) 2644 return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL); 2645 2646 sframe_encoder_write_fde_attr (contents, fdep); 2647 contents += sizeof (sframe_func_desc_attr_v3); 2648 fre_size += sizeof (sframe_func_desc_attr_v3); 2649 2650 for (j = 0; j < num_fres; j++) 2651 { 2652 fre_index = global + j; 2653 frep = &fr_info->entry[fre_index]; 2654 2655 sframe_encoder_write_fre (contents, frep, fre_type, &esz); 2656 contents += esz; 2657 fre_size += esz; /* For debugging only. */ 2658 } 2659 global += j; 2660 } 2661 2662 sframe_assert (fre_size == ehp->sfh_fre_len); 2663 sframe_assert (global == ehp->sfh_num_fres); 2664 sframe_assert ((size_t)(contents - ectx->sfe_data) == buf_size); 2665 2666 /* Sort the FDE table */ 2667 if (sort_fde_p) 2668 sframe_sort_funcdesc (ectx); 2669 2670 /* Sanity checks: 2671 - the FDE section must have been sorted by now on the start address 2672 of each function, if sorting was needed. */ 2673 if ((sort_fde_p != (sframe_encoder_get_flags (ectx) & SFRAME_F_FDE_SORTED)) 2674 || (fd_info == NULL)) 2675 return sframe_set_errno (&err, SFRAME_ERR_FDE_INVAL); 2676 2677 contents = ectx->sfe_data; 2678 /* Write out the SFrame header. The SFrame header in the encoder 2679 object has already been updated with correct offsets by the caller. */ 2680 memcpy (contents, ehp, hdr_size); 2681 contents += hdr_size; 2682 2683 /* Write out the FDE table sorted on funtion start address. */ 2684 for (i = 0; i < num_fdes; i++) 2685 { 2686 sframe_encoder_write_fde_idx (ehp, contents, &fd_info->entry[i], 2687 &fde_write_size); 2688 contents += fde_write_size; 2689 } 2690 2691 return 0; 2692 } 2693 2694 /* Serialize the contents of the encoder context ECTX and return the buffer. 2695 Sort the SFrame FDEs on start PC if SORT_FDE_P is true. ENCODED_SIZE is 2696 updated to the size of the buffer. Sets ERRP if failure. */ 2697 2698 char * 2699 sframe_encoder_write (sframe_encoder_ctx *ectx, size_t *encoded_size, 2700 bool sort_fde_p, int *errp) 2701 { 2702 sframe_header *ehp; 2703 size_t hdrsize, fsz, fresz, bufsize; 2704 int foreign_endian; 2705 2706 /* Initialize the encoded_size to zero. This makes it simpler to just 2707 return from the function in case of failure. Free'ing up of 2708 ectx->sfe_data is the responsibility of the caller. */ 2709 *encoded_size = 0; 2710 2711 if (ectx == NULL || encoded_size == NULL || errp == NULL) 2712 return sframe_ret_set_errno (errp, SFRAME_ERR_INVAL); 2713 2714 ehp = sframe_encoder_get_header (ectx); 2715 hdrsize = sframe_get_hdr_size (ehp); 2716 fsz = sframe_encoder_get_num_fidx (ectx) * sizeof (sframe_func_desc_idx_v3); 2717 fresz = ectx->sfe_fre_nbytes; 2718 2719 /* Encoder writes out data in the latest SFrame format version. */ 2720 if (sframe_encoder_get_version (ectx) != SFRAME_VERSION) 2721 return sframe_ret_set_errno (errp, SFRAME_ERR_VERSION_INVAL); 2722 2723 /* The total size of buffer is the sum of header, SFrame Function Descriptor 2724 Entries section and the FRE section. */ 2725 bufsize = hdrsize + fsz + fresz; 2726 ectx->sfe_data = (char *) malloc (bufsize); 2727 if (ectx->sfe_data == NULL) 2728 return sframe_ret_set_errno (errp, SFRAME_ERR_NOMEM); 2729 ectx->sfe_data_size = bufsize; 2730 2731 /* Update the information in the SFrame header. */ 2732 /* SFrame FDE section follows immediately after the header. */ 2733 ehp->sfh_fdeoff = 0; 2734 /* SFrame FRE section follows immediately after the SFrame FDE section. */ 2735 ehp->sfh_freoff = fsz; 2736 ehp->sfh_fre_len = fresz; 2737 2738 foreign_endian = need_swapping (ehp->sfh_abi_arch); 2739 2740 /* Write out the FDE Index and the FRE table in the sfe_data. */ 2741 if (sframe_encoder_write_sframe (ectx, sort_fde_p)) 2742 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 2743 2744 /* Endian flip the contents if necessary. */ 2745 if (foreign_endian) 2746 { 2747 if (flip_sframe (ectx->sfe_data, bufsize, 1)) 2748 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 2749 if (flip_header (ectx->sfe_data, SFRAME_VERSION)) 2750 return sframe_ret_set_errno (errp, SFRAME_ERR_BUF_INVAL); 2751 } 2752 2753 *encoded_size = bufsize; 2754 return ectx->sfe_data; 2755 } 2756