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