| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * recordmcount.h |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 15 | 16 | * |
|---|
| 16 | 17 | * This conversion to macros was done by: |
|---|
| 17 | 18 | * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. |
|---|
| 18 | | - * |
|---|
| 19 | | - * Licensed under the GNU General Public License, version 2 (GPLv2). |
|---|
| 20 | 19 | */ |
|---|
| 21 | 20 | #undef append_func |
|---|
| 22 | 21 | #undef is_fake_mcount |
|---|
| .. | .. |
|---|
| 193 | 192 | Elf32_Word const *symtab_shndx) |
|---|
| 194 | 193 | { |
|---|
| 195 | 194 | unsigned long offset; |
|---|
| 195 | + unsigned short shndx = w2(sym->st_shndx); |
|---|
| 196 | 196 | int index; |
|---|
| 197 | 197 | |
|---|
| 198 | | - if (sym->st_shndx != SHN_XINDEX) |
|---|
| 199 | | - return w2(sym->st_shndx); |
|---|
| 198 | + if (shndx > SHN_UNDEF && shndx < SHN_LORESERVE) |
|---|
| 199 | + return shndx; |
|---|
| 200 | 200 | |
|---|
| 201 | | - offset = (unsigned long)sym - (unsigned long)symtab; |
|---|
| 202 | | - index = offset / sizeof(*sym); |
|---|
| 201 | + if (shndx == SHN_XINDEX) { |
|---|
| 202 | + offset = (unsigned long)sym - (unsigned long)symtab; |
|---|
| 203 | + index = offset / sizeof(*sym); |
|---|
| 203 | 204 | |
|---|
| 204 | | - return w(symtab_shndx[index]); |
|---|
| 205 | + return w(symtab_shndx[index]); |
|---|
| 206 | + } |
|---|
| 207 | + |
|---|
| 208 | + return 0; |
|---|
| 205 | 209 | } |
|---|
| 206 | 210 | |
|---|
| 207 | 211 | static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0) |
|---|
| .. | .. |
|---|
| 251 | 255 | } |
|---|
| 252 | 256 | |
|---|
| 253 | 257 | /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ |
|---|
| 254 | | -static void append_func(Elf_Ehdr *const ehdr, |
|---|
| 258 | +static int append_func(Elf_Ehdr *const ehdr, |
|---|
| 255 | 259 | Elf_Shdr *const shstr, |
|---|
| 256 | 260 | uint_t const *const mloc0, |
|---|
| 257 | 261 | uint_t const *const mlocp, |
|---|
| .. | .. |
|---|
| 283 | 287 | set_shnum(ehdr, shdr0, new_shnum); |
|---|
| 284 | 288 | |
|---|
| 285 | 289 | /* body for new shstrtab */ |
|---|
| 286 | | - ulseek(fd_map, sb.st_size, SEEK_SET); |
|---|
| 287 | | - uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size); |
|---|
| 288 | | - uwrite(fd_map, mc_name, 1 + strlen(mc_name)); |
|---|
| 290 | + if (ulseek(sb.st_size, SEEK_SET) < 0) |
|---|
| 291 | + return -1; |
|---|
| 292 | + if (uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size) < 0) |
|---|
| 293 | + return -1; |
|---|
| 294 | + if (uwrite(mc_name, 1 + strlen(mc_name)) < 0) |
|---|
| 295 | + return -1; |
|---|
| 289 | 296 | |
|---|
| 290 | 297 | /* old(modified) Elf_Shdr table, word-byte aligned */ |
|---|
| 291 | | - ulseek(fd_map, t, SEEK_SET); |
|---|
| 298 | + if (ulseek(t, SEEK_SET) < 0) |
|---|
| 299 | + return -1; |
|---|
| 292 | 300 | t += sizeof(Elf_Shdr) * old_shnum; |
|---|
| 293 | | - uwrite(fd_map, old_shoff + (void *)ehdr, |
|---|
| 294 | | - sizeof(Elf_Shdr) * old_shnum); |
|---|
| 301 | + if (uwrite(old_shoff + (void *)ehdr, |
|---|
| 302 | + sizeof(Elf_Shdr) * old_shnum) < 0) |
|---|
| 303 | + return -1; |
|---|
| 295 | 304 | |
|---|
| 296 | 305 | /* new sections __mcount_loc and .rel__mcount_loc */ |
|---|
| 297 | 306 | t += 2*sizeof(mcsec); |
|---|
| .. | .. |
|---|
| 306 | 315 | mcsec.sh_info = 0; |
|---|
| 307 | 316 | mcsec.sh_addralign = _w(_size); |
|---|
| 308 | 317 | mcsec.sh_entsize = _w(_size); |
|---|
| 309 | | - uwrite(fd_map, &mcsec, sizeof(mcsec)); |
|---|
| 318 | + if (uwrite(&mcsec, sizeof(mcsec)) < 0) |
|---|
| 319 | + return -1; |
|---|
| 310 | 320 | |
|---|
| 311 | 321 | mcsec.sh_name = w(old_shstr_sh_size); |
|---|
| 312 | 322 | mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize) |
|---|
| .. | .. |
|---|
| 320 | 330 | mcsec.sh_info = w(old_shnum); |
|---|
| 321 | 331 | mcsec.sh_addralign = _w(_size); |
|---|
| 322 | 332 | mcsec.sh_entsize = _w(rel_entsize); |
|---|
| 323 | | - uwrite(fd_map, &mcsec, sizeof(mcsec)); |
|---|
| 324 | 333 | |
|---|
| 325 | | - uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0); |
|---|
| 326 | | - uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0); |
|---|
| 334 | + if (uwrite(&mcsec, sizeof(mcsec)) < 0) |
|---|
| 335 | + return -1; |
|---|
| 336 | + |
|---|
| 337 | + if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0) |
|---|
| 338 | + return -1; |
|---|
| 339 | + if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0) |
|---|
| 340 | + return -1; |
|---|
| 327 | 341 | |
|---|
| 328 | 342 | ehdr->e_shoff = _w(new_e_shoff); |
|---|
| 329 | | - ulseek(fd_map, 0, SEEK_SET); |
|---|
| 330 | | - uwrite(fd_map, ehdr, sizeof(*ehdr)); |
|---|
| 343 | + if (ulseek(0, SEEK_SET) < 0) |
|---|
| 344 | + return -1; |
|---|
| 345 | + if (uwrite(ehdr, sizeof(*ehdr)) < 0) |
|---|
| 346 | + return -1; |
|---|
| 347 | + return 0; |
|---|
| 331 | 348 | } |
|---|
| 332 | 349 | |
|---|
| 333 | 350 | static unsigned get_mcountsym(Elf_Sym const *const sym0, |
|---|
| .. | .. |
|---|
| 431 | 448 | * that are not going to be traced. The mcount calls here will be converted |
|---|
| 432 | 449 | * into nops. |
|---|
| 433 | 450 | */ |
|---|
| 434 | | -static void nop_mcount(Elf_Shdr const *const relhdr, |
|---|
| 435 | | - Elf_Ehdr const *const ehdr, |
|---|
| 436 | | - const char *const txtname) |
|---|
| 451 | +static int nop_mcount(Elf_Shdr const *const relhdr, |
|---|
| 452 | + Elf_Ehdr const *const ehdr, |
|---|
| 453 | + const char *const txtname) |
|---|
| 437 | 454 | { |
|---|
| 438 | 455 | Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) |
|---|
| 439 | 456 | + (void *)ehdr); |
|---|
| .. | .. |
|---|
| 464 | 481 | once = 1; |
|---|
| 465 | 482 | /* just warn? */ |
|---|
| 466 | 483 | if (!make_nop) |
|---|
| 467 | | - return; |
|---|
| 484 | + return 0; |
|---|
| 468 | 485 | } |
|---|
| 469 | 486 | } |
|---|
| 470 | 487 | |
|---|
| .. | .. |
|---|
| 476 | 493 | Elf_Rel rel; |
|---|
| 477 | 494 | rel = *(Elf_Rel *)relp; |
|---|
| 478 | 495 | Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop); |
|---|
| 479 | | - ulseek(fd_map, (void *)relp - (void *)ehdr, SEEK_SET); |
|---|
| 480 | | - uwrite(fd_map, &rel, sizeof(rel)); |
|---|
| 496 | + if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0) |
|---|
| 497 | + return -1; |
|---|
| 498 | + if (uwrite(&rel, sizeof(rel)) < 0) |
|---|
| 499 | + return -1; |
|---|
| 481 | 500 | } |
|---|
| 482 | 501 | relp = (Elf_Rel const *)(rel_entsize + (void *)relp); |
|---|
| 483 | 502 | } |
|---|
| 503 | + return 0; |
|---|
| 484 | 504 | } |
|---|
| 485 | | - |
|---|
| 486 | 505 | |
|---|
| 487 | 506 | /* |
|---|
| 488 | 507 | * Find a symbol in the given section, to be used as the base for relocating |
|---|
| .. | .. |
|---|
| 494 | 513 | * Num: Value Size Type Bind Vis Ndx Name |
|---|
| 495 | 514 | * 2: 00000000 0 SECTION LOCAL DEFAULT 1 |
|---|
| 496 | 515 | */ |
|---|
| 497 | | -static unsigned find_secsym_ndx(unsigned const txtndx, |
|---|
| 516 | +static int find_secsym_ndx(unsigned const txtndx, |
|---|
| 498 | 517 | char const *const txtname, |
|---|
| 499 | 518 | uint_t *const recvalp, |
|---|
| 519 | + unsigned int *sym_index, |
|---|
| 500 | 520 | Elf_Shdr const *const symhdr, |
|---|
| 501 | 521 | Elf32_Word const *symtab, |
|---|
| 502 | 522 | Elf32_Word const *symtab_shndx, |
|---|
| .. | .. |
|---|
| 520 | 540 | continue; |
|---|
| 521 | 541 | |
|---|
| 522 | 542 | *recvalp = _w(symp->st_value); |
|---|
| 523 | | - return symp - sym0; |
|---|
| 543 | + *sym_index = symp - sym0; |
|---|
| 544 | + return 0; |
|---|
| 524 | 545 | } |
|---|
| 525 | 546 | } |
|---|
| 526 | 547 | fprintf(stderr, "Cannot find symbol for section %u: %s.\n", |
|---|
| 527 | 548 | txtndx, txtname); |
|---|
| 528 | | - fail_file(); |
|---|
| 549 | + return -1; |
|---|
| 529 | 550 | } |
|---|
| 530 | 551 | |
|---|
| 531 | | - |
|---|
| 532 | 552 | /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */ |
|---|
| 533 | | -static char const * |
|---|
| 534 | | -__has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ |
|---|
| 535 | | - Elf_Shdr const *const shdr0, |
|---|
| 536 | | - char const *const shstrtab, |
|---|
| 537 | | - char const *const fname) |
|---|
| 553 | +static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */ |
|---|
| 554 | + Elf_Shdr const *const shdr0, |
|---|
| 555 | + char const *const shstrtab, |
|---|
| 556 | + char const *const fname) |
|---|
| 538 | 557 | { |
|---|
| 539 | 558 | /* .sh_info depends on .sh_type == SHT_REL[,A] */ |
|---|
| 540 | 559 | Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)]; |
|---|
| .. | .. |
|---|
| 543 | 562 | if (strcmp("__mcount_loc", txtname) == 0) { |
|---|
| 544 | 563 | fprintf(stderr, "warning: __mcount_loc already exists: %s\n", |
|---|
| 545 | 564 | fname); |
|---|
| 546 | | - succeed_file(); |
|---|
| 565 | + return already_has_rel_mcount; |
|---|
| 547 | 566 | } |
|---|
| 548 | 567 | if (w(txthdr->sh_type) != SHT_PROGBITS || |
|---|
| 549 | 568 | !(_w(txthdr->sh_flags) & SHF_EXECINSTR)) |
|---|
| .. | .. |
|---|
| 573 | 592 | |
|---|
| 574 | 593 | for (; nhdr; --nhdr, ++shdrp) { |
|---|
| 575 | 594 | txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname); |
|---|
| 595 | + if (txtname == already_has_rel_mcount) { |
|---|
| 596 | + totrelsz = 0; |
|---|
| 597 | + break; |
|---|
| 598 | + } |
|---|
| 576 | 599 | if (txtname && is_mcounted_section_name(txtname)) |
|---|
| 577 | 600 | totrelsz += _w(shdrp->sh_size); |
|---|
| 578 | 601 | } |
|---|
| .. | .. |
|---|
| 580 | 603 | } |
|---|
| 581 | 604 | |
|---|
| 582 | 605 | /* Overall supervision for Elf32 ET_REL file. */ |
|---|
| 583 | | -static void |
|---|
| 584 | | -do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) |
|---|
| 606 | +static int do_func(Elf_Ehdr *const ehdr, char const *const fname, |
|---|
| 607 | + unsigned const reltype) |
|---|
| 585 | 608 | { |
|---|
| 586 | 609 | Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) |
|---|
| 587 | 610 | + (void *)ehdr); |
|---|
| .. | .. |
|---|
| 597 | 620 | Elf32_Word *symtab_shndx; |
|---|
| 598 | 621 | |
|---|
| 599 | 622 | /* Upper bound on space: assume all relevant relocs are for mcount. */ |
|---|
| 600 | | - unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname); |
|---|
| 601 | | - Elf_Rel *const mrel0 = umalloc(totrelsz); |
|---|
| 602 | | - Elf_Rel * mrelp = mrel0; |
|---|
| 623 | + unsigned totrelsz; |
|---|
| 603 | 624 | |
|---|
| 604 | | - /* 2*sizeof(address) <= sizeof(Elf_Rel) */ |
|---|
| 605 | | - uint_t *const mloc0 = umalloc(totrelsz>>1); |
|---|
| 606 | | - uint_t * mlocp = mloc0; |
|---|
| 625 | + Elf_Rel * mrel0; |
|---|
| 626 | + Elf_Rel * mrelp; |
|---|
| 627 | + |
|---|
| 628 | + uint_t * mloc0; |
|---|
| 629 | + uint_t * mlocp; |
|---|
| 607 | 630 | |
|---|
| 608 | 631 | unsigned rel_entsize = 0; |
|---|
| 609 | 632 | unsigned symsec_sh_link = 0; |
|---|
| 633 | + |
|---|
| 634 | + int result = 0; |
|---|
| 635 | + |
|---|
| 636 | + totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname); |
|---|
| 637 | + if (totrelsz == 0) |
|---|
| 638 | + return 0; |
|---|
| 639 | + mrel0 = umalloc(totrelsz); |
|---|
| 640 | + mrelp = mrel0; |
|---|
| 641 | + if (!mrel0) |
|---|
| 642 | + return -1; |
|---|
| 643 | + |
|---|
| 644 | + /* 2*sizeof(address) <= sizeof(Elf_Rel) */ |
|---|
| 645 | + mloc0 = umalloc(totrelsz>>1); |
|---|
| 646 | + mlocp = mloc0; |
|---|
| 647 | + if (!mloc0) { |
|---|
| 648 | + free(mrel0); |
|---|
| 649 | + return -1; |
|---|
| 650 | + } |
|---|
| 610 | 651 | |
|---|
| 611 | 652 | find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx); |
|---|
| 612 | 653 | |
|---|
| 613 | 654 | for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { |
|---|
| 614 | 655 | char const *const txtname = has_rel_mcount(relhdr, shdr0, |
|---|
| 615 | 656 | shstrtab, fname); |
|---|
| 657 | + if (txtname == already_has_rel_mcount) { |
|---|
| 658 | + result = 0; |
|---|
| 659 | + file_updated = 0; |
|---|
| 660 | + goto out; /* Nothing to be done; don't append! */ |
|---|
| 661 | + } |
|---|
| 616 | 662 | if (txtname && is_mcounted_section_name(txtname)) { |
|---|
| 663 | + unsigned int recsym; |
|---|
| 617 | 664 | uint_t recval = 0; |
|---|
| 618 | | - unsigned const recsym = find_secsym_ndx( |
|---|
| 619 | | - w(relhdr->sh_info), txtname, &recval, |
|---|
| 620 | | - &shdr0[symsec_sh_link = w(relhdr->sh_link)], |
|---|
| 621 | | - symtab, symtab_shndx, |
|---|
| 622 | | - ehdr); |
|---|
| 665 | + |
|---|
| 666 | + symsec_sh_link = w(relhdr->sh_link); |
|---|
| 667 | + result = find_secsym_ndx(w(relhdr->sh_info), txtname, |
|---|
| 668 | + &recval, &recsym, |
|---|
| 669 | + &shdr0[symsec_sh_link], |
|---|
| 670 | + symtab, symtab_shndx, |
|---|
| 671 | + ehdr); |
|---|
| 672 | + if (result) |
|---|
| 673 | + goto out; |
|---|
| 623 | 674 | |
|---|
| 624 | 675 | rel_entsize = _w(relhdr->sh_entsize); |
|---|
| 625 | 676 | mlocp = sift_rel_mcount(mlocp, |
|---|
| .. | .. |
|---|
| 630 | 681 | * This section is ignored by ftrace, but still |
|---|
| 631 | 682 | * has mcount calls. Convert them to nops now. |
|---|
| 632 | 683 | */ |
|---|
| 633 | | - nop_mcount(relhdr, ehdr, txtname); |
|---|
| 684 | + if (nop_mcount(relhdr, ehdr, txtname) < 0) { |
|---|
| 685 | + result = -1; |
|---|
| 686 | + goto out; |
|---|
| 687 | + } |
|---|
| 634 | 688 | } |
|---|
| 635 | 689 | } |
|---|
| 636 | | - if (mloc0 != mlocp) { |
|---|
| 637 | | - append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp, |
|---|
| 638 | | - rel_entsize, symsec_sh_link); |
|---|
| 639 | | - } |
|---|
| 690 | + if (!result && mloc0 != mlocp) |
|---|
| 691 | + result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp, |
|---|
| 692 | + rel_entsize, symsec_sh_link); |
|---|
| 693 | +out: |
|---|
| 640 | 694 | free(mrel0); |
|---|
| 641 | 695 | free(mloc0); |
|---|
| 696 | + return result; |
|---|
| 642 | 697 | } |
|---|