root/scripts/recordmcount.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. fn_is_fake_mcount
  2. fn_ELF_R_SYM
  3. fn_ELF_R_INFO
  4. MIPS_is_fake_mcount
  5. append_func
  6. get_mcountsym
  7. get_sym_str_and_relp
  8. sift_rel_mcount
  9. nop_mcount
  10. find_secsym_ndx
  11. __has_rel_mcount
  12. has_rel_mcount
  13. tot_relsize
  14. do_func

   1 /* SPDX-License-Identifier: GPL-2.0-only */
   2 /*
   3  * recordmcount.h
   4  *
   5  * This code was taken out of recordmcount.c written by
   6  * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
   7  *
   8  * The original code had the same algorithms for both 32bit
   9  * and 64bit ELF files, but the code was duplicated to support
  10  * the difference in structures that were used. This
  11  * file creates a macro of everything that is different between
  12  * the 64 and 32 bit code, such that by including this header
  13  * twice we can create both sets of functions by including this
  14  * header once with RECORD_MCOUNT_64 undefined, and again with
  15  * it defined.
  16  *
  17  * This conversion to macros was done by:
  18  * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
  19  */
  20 #undef append_func
  21 #undef is_fake_mcount
  22 #undef fn_is_fake_mcount
  23 #undef MIPS_is_fake_mcount
  24 #undef mcount_adjust
  25 #undef sift_rel_mcount
  26 #undef nop_mcount
  27 #undef find_secsym_ndx
  28 #undef __has_rel_mcount
  29 #undef has_rel_mcount
  30 #undef tot_relsize
  31 #undef get_mcountsym
  32 #undef get_sym_str_and_relp
  33 #undef do_func
  34 #undef Elf_Addr
  35 #undef Elf_Ehdr
  36 #undef Elf_Shdr
  37 #undef Elf_Rel
  38 #undef Elf_Rela
  39 #undef Elf_Sym
  40 #undef ELF_R_SYM
  41 #undef Elf_r_sym
  42 #undef ELF_R_INFO
  43 #undef Elf_r_info
  44 #undef ELF_ST_BIND
  45 #undef ELF_ST_TYPE
  46 #undef fn_ELF_R_SYM
  47 #undef fn_ELF_R_INFO
  48 #undef uint_t
  49 #undef _w
  50 #undef _align
  51 #undef _size
  52 
  53 #ifdef RECORD_MCOUNT_64
  54 # define append_func            append64
  55 # define sift_rel_mcount        sift64_rel_mcount
  56 # define nop_mcount             nop_mcount_64
  57 # define find_secsym_ndx        find64_secsym_ndx
  58 # define __has_rel_mcount       __has64_rel_mcount
  59 # define has_rel_mcount         has64_rel_mcount
  60 # define tot_relsize            tot64_relsize
  61 # define get_sym_str_and_relp   get_sym_str_and_relp_64
  62 # define do_func                do64
  63 # define get_mcountsym          get_mcountsym_64
  64 # define is_fake_mcount         is_fake_mcount64
  65 # define fn_is_fake_mcount      fn_is_fake_mcount64
  66 # define MIPS_is_fake_mcount    MIPS64_is_fake_mcount
  67 # define mcount_adjust          mcount_adjust_64
  68 # define Elf_Addr               Elf64_Addr
  69 # define Elf_Ehdr               Elf64_Ehdr
  70 # define Elf_Shdr               Elf64_Shdr
  71 # define Elf_Rel                Elf64_Rel
  72 # define Elf_Rela               Elf64_Rela
  73 # define Elf_Sym                Elf64_Sym
  74 # define ELF_R_SYM              ELF64_R_SYM
  75 # define Elf_r_sym              Elf64_r_sym
  76 # define ELF_R_INFO             ELF64_R_INFO
  77 # define Elf_r_info             Elf64_r_info
  78 # define ELF_ST_BIND            ELF64_ST_BIND
  79 # define ELF_ST_TYPE            ELF64_ST_TYPE
  80 # define fn_ELF_R_SYM           fn_ELF64_R_SYM
  81 # define fn_ELF_R_INFO          fn_ELF64_R_INFO
  82 # define uint_t                 uint64_t
  83 # define _w                     w8
  84 # define _align                 7u
  85 # define _size                  8
  86 #else
  87 # define append_func            append32
  88 # define sift_rel_mcount        sift32_rel_mcount
  89 # define nop_mcount             nop_mcount_32
  90 # define find_secsym_ndx        find32_secsym_ndx
  91 # define __has_rel_mcount       __has32_rel_mcount
  92 # define has_rel_mcount         has32_rel_mcount
  93 # define tot_relsize            tot32_relsize
  94 # define get_sym_str_and_relp   get_sym_str_and_relp_32
  95 # define do_func                do32
  96 # define get_mcountsym          get_mcountsym_32
  97 # define is_fake_mcount         is_fake_mcount32
  98 # define fn_is_fake_mcount      fn_is_fake_mcount32
  99 # define MIPS_is_fake_mcount    MIPS32_is_fake_mcount
 100 # define mcount_adjust          mcount_adjust_32
 101 # define Elf_Addr               Elf32_Addr
 102 # define Elf_Ehdr               Elf32_Ehdr
 103 # define Elf_Shdr               Elf32_Shdr
 104 # define Elf_Rel                Elf32_Rel
 105 # define Elf_Rela               Elf32_Rela
 106 # define Elf_Sym                Elf32_Sym
 107 # define ELF_R_SYM              ELF32_R_SYM
 108 # define Elf_r_sym              Elf32_r_sym
 109 # define ELF_R_INFO             ELF32_R_INFO
 110 # define Elf_r_info             Elf32_r_info
 111 # define ELF_ST_BIND            ELF32_ST_BIND
 112 # define ELF_ST_TYPE            ELF32_ST_TYPE
 113 # define fn_ELF_R_SYM           fn_ELF32_R_SYM
 114 # define fn_ELF_R_INFO          fn_ELF32_R_INFO
 115 # define uint_t                 uint32_t
 116 # define _w                     w
 117 # define _align                 3u
 118 # define _size                  4
 119 #endif
 120 
 121 /* Functions and pointers that do_file() may override for specific e_machine. */
 122 static int fn_is_fake_mcount(Elf_Rel const *rp)
 123 {
 124         return 0;
 125 }
 126 static int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount;
 127 
 128 static uint_t fn_ELF_R_SYM(Elf_Rel const *rp)
 129 {
 130         return ELF_R_SYM(_w(rp->r_info));
 131 }
 132 static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM;
 133 
 134 static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
 135 {
 136         rp->r_info = _w(ELF_R_INFO(sym, type));
 137 }
 138 static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
 139 
 140 static int mcount_adjust = 0;
 141 
 142 /*
 143  * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st
 144  * _mcount symbol is needed for dynamic function tracer, with it, to disable
 145  * tracing(ftrace_make_nop), the instruction in the position is replaced with
 146  * the "b label" instruction, to enable tracing(ftrace_make_call), replace the
 147  * instruction back. So, here, we set the 2nd one as fake and filter it.
 148  *
 149  * c:   3c030000        lui     v1,0x0          <-->    b       label
 150  *              c: R_MIPS_HI16  _mcount
 151  *              c: R_MIPS_NONE  *ABS*
 152  *              c: R_MIPS_NONE  *ABS*
 153  * 10:  64630000        daddiu  v1,v1,0
 154  *              10: R_MIPS_LO16 _mcount
 155  *              10: R_MIPS_NONE *ABS*
 156  *              10: R_MIPS_NONE *ABS*
 157  * 14:  03e0082d        move    at,ra
 158  * 18:  0060f809        jalr    v1
 159  * label:
 160  */
 161 #define MIPS_FAKEMCOUNT_OFFSET  4
 162 
 163 static int MIPS_is_fake_mcount(Elf_Rel const *rp)
 164 {
 165         static Elf_Addr old_r_offset = ~(Elf_Addr)0;
 166         Elf_Addr current_r_offset = _w(rp->r_offset);
 167         int is_fake;
 168 
 169         is_fake = (old_r_offset != ~(Elf_Addr)0) &&
 170                 (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
 171         old_r_offset = current_r_offset;
 172 
 173         return is_fake;
 174 }
 175 
 176 /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
 177 static int append_func(Elf_Ehdr *const ehdr,
 178                         Elf_Shdr *const shstr,
 179                         uint_t const *const mloc0,
 180                         uint_t const *const mlocp,
 181                         Elf_Rel const *const mrel0,
 182                         Elf_Rel const *const mrelp,
 183                         unsigned int const rel_entsize,
 184                         unsigned int const symsec_sh_link)
 185 {
 186         /* Begin constructing output file */
 187         Elf_Shdr mcsec;
 188         char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
 189                 ? ".rela__mcount_loc"
 190                 :  ".rel__mcount_loc";
 191         unsigned const old_shnum = w2(ehdr->e_shnum);
 192         uint_t const old_shoff = _w(ehdr->e_shoff);
 193         uint_t const old_shstr_sh_size   = _w(shstr->sh_size);
 194         uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
 195         uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
 196         uint_t new_e_shoff;
 197 
 198         shstr->sh_size = _w(t);
 199         shstr->sh_offset = _w(sb.st_size);
 200         t += sb.st_size;
 201         t += (_align & -t);  /* word-byte align */
 202         new_e_shoff = t;
 203 
 204         /* body for new shstrtab */
 205         if (ulseek(sb.st_size, SEEK_SET) < 0)
 206                 return -1;
 207         if (uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size) < 0)
 208                 return -1;
 209         if (uwrite(mc_name, 1 + strlen(mc_name)) < 0)
 210                 return -1;
 211 
 212         /* old(modified) Elf_Shdr table, word-byte aligned */
 213         if (ulseek(t, SEEK_SET) < 0)
 214                 return -1;
 215         t += sizeof(Elf_Shdr) * old_shnum;
 216         if (uwrite(old_shoff + (void *)ehdr,
 217                sizeof(Elf_Shdr) * old_shnum) < 0)
 218                 return -1;
 219 
 220         /* new sections __mcount_loc and .rel__mcount_loc */
 221         t += 2*sizeof(mcsec);
 222         mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
 223                 + old_shstr_sh_size);
 224         mcsec.sh_type = w(SHT_PROGBITS);
 225         mcsec.sh_flags = _w(SHF_ALLOC);
 226         mcsec.sh_addr = 0;
 227         mcsec.sh_offset = _w(t);
 228         mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
 229         mcsec.sh_link = 0;
 230         mcsec.sh_info = 0;
 231         mcsec.sh_addralign = _w(_size);
 232         mcsec.sh_entsize = _w(_size);
 233         if (uwrite(&mcsec, sizeof(mcsec)) < 0)
 234                 return -1;
 235 
 236         mcsec.sh_name = w(old_shstr_sh_size);
 237         mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
 238                 ? w(SHT_RELA)
 239                 : w(SHT_REL);
 240         mcsec.sh_flags = 0;
 241         mcsec.sh_addr = 0;
 242         mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
 243         mcsec.sh_size   = _w((void *)mrelp - (void *)mrel0);
 244         mcsec.sh_link = w(symsec_sh_link);
 245         mcsec.sh_info = w(old_shnum);
 246         mcsec.sh_addralign = _w(_size);
 247         mcsec.sh_entsize = _w(rel_entsize);
 248 
 249         if (uwrite(&mcsec, sizeof(mcsec)) < 0)
 250                 return -1;
 251 
 252         if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0)
 253                 return -1;
 254         if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0)
 255                 return -1;
 256 
 257         ehdr->e_shoff = _w(new_e_shoff);
 258         ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum));  /* {.rel,}__mcount_loc */
 259         if (ulseek(0, SEEK_SET) < 0)
 260                 return -1;
 261         if (uwrite(ehdr, sizeof(*ehdr)) < 0)
 262                 return -1;
 263         return 0;
 264 }
 265 
 266 static unsigned get_mcountsym(Elf_Sym const *const sym0,
 267                               Elf_Rel const *relp,
 268                               char const *const str0)
 269 {
 270         unsigned mcountsym = 0;
 271 
 272         Elf_Sym const *const symp =
 273                 &sym0[Elf_r_sym(relp)];
 274         char const *symname = &str0[w(symp->st_name)];
 275         char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
 276         char const *fentry = "__fentry__";
 277 
 278         if (symname[0] == '.')
 279                 ++symname;  /* ppc64 hack */
 280         if (strcmp(mcount, symname) == 0 ||
 281             (altmcount && strcmp(altmcount, symname) == 0) ||
 282             (strcmp(fentry, symname) == 0))
 283                 mcountsym = Elf_r_sym(relp);
 284 
 285         return mcountsym;
 286 }
 287 
 288 static void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
 289                                  Elf_Ehdr const *const ehdr,
 290                                  Elf_Sym const **sym0,
 291                                  char const **str0,
 292                                  Elf_Rel const **relp)
 293 {
 294         Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
 295                 + (void *)ehdr);
 296         unsigned const symsec_sh_link = w(relhdr->sh_link);
 297         Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
 298         Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
 299         Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
 300                 + (void *)ehdr);
 301 
 302         *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
 303                                   + (void *)ehdr);
 304 
 305         *str0 = (char const *)(_w(strsec->sh_offset)
 306                                + (void *)ehdr);
 307 
 308         *relp = rel0;
 309 }
 310 
 311 /*
 312  * Look at the relocations in order to find the calls to mcount.
 313  * Accumulate the section offsets that are found, and their relocation info,
 314  * onto the end of the existing arrays.
 315  */
 316 static uint_t *sift_rel_mcount(uint_t *mlocp,
 317                                unsigned const offbase,
 318                                Elf_Rel **const mrelpp,
 319                                Elf_Shdr const *const relhdr,
 320                                Elf_Ehdr const *const ehdr,
 321                                unsigned const recsym,
 322                                uint_t const recval,
 323                                unsigned const reltype)
 324 {
 325         uint_t *const mloc0 = mlocp;
 326         Elf_Rel *mrelp = *mrelpp;
 327         Elf_Sym const *sym0;
 328         char const *str0;
 329         Elf_Rel const *relp;
 330         unsigned rel_entsize = _w(relhdr->sh_entsize);
 331         unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
 332         unsigned mcountsym = 0;
 333         unsigned t;
 334 
 335         get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
 336 
 337         for (t = nrel; t; --t) {
 338                 if (!mcountsym)
 339                         mcountsym = get_mcountsym(sym0, relp, str0);
 340 
 341                 if (mcountsym && mcountsym == Elf_r_sym(relp) &&
 342                                 !is_fake_mcount(relp)) {
 343                         uint_t const addend =
 344                                 _w(_w(relp->r_offset) - recval + mcount_adjust);
 345                         mrelp->r_offset = _w(offbase
 346                                 + ((void *)mlocp - (void *)mloc0));
 347                         Elf_r_info(mrelp, recsym, reltype);
 348                         if (rel_entsize == sizeof(Elf_Rela)) {
 349                                 ((Elf_Rela *)mrelp)->r_addend = addend;
 350                                 *mlocp++ = 0;
 351                         } else
 352                                 *mlocp++ = addend;
 353 
 354                         mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
 355                 }
 356                 relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
 357         }
 358         *mrelpp = mrelp;
 359         return mlocp;
 360 }
 361 
 362 /*
 363  * Read the relocation table again, but this time its called on sections
 364  * that are not going to be traced. The mcount calls here will be converted
 365  * into nops.
 366  */
 367 static int nop_mcount(Elf_Shdr const *const relhdr,
 368                       Elf_Ehdr const *const ehdr,
 369                       const char *const txtname)
 370 {
 371         Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
 372                 + (void *)ehdr);
 373         Elf_Sym const *sym0;
 374         char const *str0;
 375         Elf_Rel const *relp;
 376         Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
 377         unsigned rel_entsize = _w(relhdr->sh_entsize);
 378         unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
 379         unsigned mcountsym = 0;
 380         unsigned t;
 381         int once = 0;
 382 
 383         get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
 384 
 385         for (t = nrel; t; --t) {
 386                 int ret = -1;
 387 
 388                 if (!mcountsym)
 389                         mcountsym = get_mcountsym(sym0, relp, str0);
 390 
 391                 if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
 392                         if (make_nop)
 393                                 ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
 394                         if (warn_on_notrace_sect && !once) {
 395                                 printf("Section %s has mcount callers being ignored\n",
 396                                        txtname);
 397                                 once = 1;
 398                                 /* just warn? */
 399                                 if (!make_nop)
 400                                         return 0;
 401                         }
 402                 }
 403 
 404                 /*
 405                  * If we successfully removed the mcount, mark the relocation
 406                  * as a nop (don't do anything with it).
 407                  */
 408                 if (!ret) {
 409                         Elf_Rel rel;
 410                         rel = *(Elf_Rel *)relp;
 411                         Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
 412                         if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0)
 413                                 return -1;
 414                         if (uwrite(&rel, sizeof(rel)) < 0)
 415                                 return -1;
 416                 }
 417                 relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
 418         }
 419         return 0;
 420 }
 421 
 422 /*
 423  * Find a symbol in the given section, to be used as the base for relocating
 424  * the table of offsets of calls to mcount.  A local or global symbol suffices,
 425  * but avoid a Weak symbol because it may be overridden; the change in value
 426  * would invalidate the relocations of the offsets of the calls to mcount.
 427  * Often the found symbol will be the unnamed local symbol generated by
 428  * GNU 'as' for the start of each section.  For example:
 429  *    Num:    Value  Size Type    Bind   Vis      Ndx Name
 430  *      2: 00000000     0 SECTION LOCAL  DEFAULT    1
 431  */
 432 static int find_secsym_ndx(unsigned const txtndx,
 433                                 char const *const txtname,
 434                                 uint_t *const recvalp,
 435                                 unsigned int *sym_index,
 436                                 Elf_Shdr const *const symhdr,
 437                                 Elf_Ehdr const *const ehdr)
 438 {
 439         Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
 440                 + (void *)ehdr);
 441         unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
 442         Elf_Sym const *symp;
 443         unsigned t;
 444 
 445         for (symp = sym0, t = nsym; t; --t, ++symp) {
 446                 unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
 447 
 448                 if (txtndx == w2(symp->st_shndx)
 449                         /* avoid STB_WEAK */
 450                     && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
 451                         /* function symbols on ARM have quirks, avoid them */
 452                         if (w2(ehdr->e_machine) == EM_ARM
 453                             && ELF_ST_TYPE(symp->st_info) == STT_FUNC)
 454                                 continue;
 455 
 456                         *recvalp = _w(symp->st_value);
 457                         *sym_index = symp - sym0;
 458                         return 0;
 459                 }
 460         }
 461         fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
 462                 txtndx, txtname);
 463         return -1;
 464 }
 465 
 466 /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
 467 static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
 468                                      Elf_Shdr const *const shdr0,
 469                                      char const *const shstrtab,
 470                                      char const *const fname)
 471 {
 472         /* .sh_info depends on .sh_type == SHT_REL[,A] */
 473         Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
 474         char const *const txtname = &shstrtab[w(txthdr->sh_name)];
 475 
 476         if (strcmp("__mcount_loc", txtname) == 0) {
 477                 fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
 478                         fname);
 479                 return already_has_rel_mcount;
 480         }
 481         if (w(txthdr->sh_type) != SHT_PROGBITS ||
 482             !(_w(txthdr->sh_flags) & SHF_EXECINSTR))
 483                 return NULL;
 484         return txtname;
 485 }
 486 
 487 static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
 488                                   Elf_Shdr const *const shdr0,
 489                                   char const *const shstrtab,
 490                                   char const *const fname)
 491 {
 492         if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA)
 493                 return NULL;
 494         return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
 495 }
 496 
 497 
 498 static unsigned tot_relsize(Elf_Shdr const *const shdr0,
 499                             unsigned nhdr,
 500                             const char *const shstrtab,
 501                             const char *const fname)
 502 {
 503         unsigned totrelsz = 0;
 504         Elf_Shdr const *shdrp = shdr0;
 505         char const *txtname;
 506 
 507         for (; nhdr; --nhdr, ++shdrp) {
 508                 txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
 509                 if (txtname == already_has_rel_mcount) {
 510                         totrelsz = 0;
 511                         break;
 512                 }
 513                 if (txtname && is_mcounted_section_name(txtname))
 514                         totrelsz += _w(shdrp->sh_size);
 515         }
 516         return totrelsz;
 517 }
 518 
 519 
 520 /* Overall supervision for Elf32 ET_REL file. */
 521 static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
 522                    unsigned const reltype)
 523 {
 524         Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
 525                 + (void *)ehdr);
 526         unsigned const nhdr = w2(ehdr->e_shnum);
 527         Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
 528         char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
 529                 + (void *)ehdr);
 530 
 531         Elf_Shdr const *relhdr;
 532         unsigned k;
 533 
 534         /* Upper bound on space: assume all relevant relocs are for mcount. */
 535         unsigned       totrelsz;
 536 
 537         Elf_Rel *      mrel0;
 538         Elf_Rel *      mrelp;
 539 
 540         uint_t *      mloc0;
 541         uint_t *      mlocp;
 542 
 543         unsigned rel_entsize = 0;
 544         unsigned symsec_sh_link = 0;
 545 
 546         int result = 0;
 547 
 548         totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
 549         if (totrelsz == 0)
 550                 return 0;
 551         mrel0 = umalloc(totrelsz);
 552         mrelp = mrel0;
 553         if (!mrel0)
 554                 return -1;
 555 
 556         /* 2*sizeof(address) <= sizeof(Elf_Rel) */
 557         mloc0 = umalloc(totrelsz>>1);
 558         mlocp = mloc0;
 559         if (!mloc0) {
 560                 free(mrel0);
 561                 return -1;
 562         }
 563 
 564         for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
 565                 char const *const txtname = has_rel_mcount(relhdr, shdr0,
 566                         shstrtab, fname);
 567                 if (txtname == already_has_rel_mcount) {
 568                         result = 0;
 569                         file_updated = 0;
 570                         goto out; /* Nothing to be done; don't append! */
 571                 }
 572                 if (txtname && is_mcounted_section_name(txtname)) {
 573                         unsigned int recsym;
 574                         uint_t recval = 0;
 575 
 576                         symsec_sh_link = w(relhdr->sh_link);
 577                         result = find_secsym_ndx(w(relhdr->sh_info), txtname,
 578                                                 &recval, &recsym,
 579                                                 &shdr0[symsec_sh_link],
 580                                                 ehdr);
 581                         if (result)
 582                                 goto out;
 583 
 584                         rel_entsize = _w(relhdr->sh_entsize);
 585                         mlocp = sift_rel_mcount(mlocp,
 586                                 (void *)mlocp - (void *)mloc0, &mrelp,
 587                                 relhdr, ehdr, recsym, recval, reltype);
 588                 } else if (txtname && (warn_on_notrace_sect || make_nop)) {
 589                         /*
 590                          * This section is ignored by ftrace, but still
 591                          * has mcount calls. Convert them to nops now.
 592                          */
 593                         if (nop_mcount(relhdr, ehdr, txtname) < 0) {
 594                                 result = -1;
 595                                 goto out;
 596                         }
 597                 }
 598         }
 599         if (!result && mloc0 != mlocp)
 600                 result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
 601                                      rel_entsize, symsec_sh_link);
 602 out:
 603         free(mrel0);
 604         free(mloc0);
 605         return result;
 606 }

/* [<][>][^][v][top][bottom][index][help] */