.. | .. |
---|
| 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 | } |
---|