1c28d5077SSteven Rostedt /* 2c28d5077SSteven Rostedt * recordmcount.h 3c28d5077SSteven Rostedt * 4c28d5077SSteven Rostedt * This code was taken out of recordmcount.c written by 5c28d5077SSteven Rostedt * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. 6c28d5077SSteven Rostedt * 7c28d5077SSteven Rostedt * The original code had the same algorithms for both 32bit 8c28d5077SSteven Rostedt * and 64bit ELF files, but the code was duplicated to support 9c28d5077SSteven Rostedt * the difference in structures that were used. This 10c28d5077SSteven Rostedt * file creates a macro of everything that is different between 11c28d5077SSteven Rostedt * the 64 and 32 bit code, such that by including this header 12c28d5077SSteven Rostedt * twice we can create both sets of functions by including this 13c28d5077SSteven Rostedt * header once with RECORD_MCOUNT_64 undefined, and again with 14c28d5077SSteven Rostedt * it defined. 15c28d5077SSteven Rostedt * 16c28d5077SSteven Rostedt * This conversion to macros was done by: 17c28d5077SSteven Rostedt * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. 18c28d5077SSteven Rostedt * 19c28d5077SSteven Rostedt * Licensed under the GNU General Public License, version 2 (GPLv2). 20c28d5077SSteven Rostedt */ 21c28d5077SSteven Rostedt #undef append_func 22412910cdSWu Zhangjin #undef is_fake_mcount 23412910cdSWu Zhangjin #undef fn_is_fake_mcount 24412910cdSWu Zhangjin #undef MIPS_is_fake_mcount 2507d8b595SMartin Schwidefsky #undef mcount_adjust 26c28d5077SSteven Rostedt #undef sift_rel_mcount 27ffd618faSSteven Rostedt #undef nop_mcount 28c28d5077SSteven Rostedt #undef find_secsym_ndx 29c28d5077SSteven Rostedt #undef __has_rel_mcount 30c28d5077SSteven Rostedt #undef has_rel_mcount 31c28d5077SSteven Rostedt #undef tot_relsize 3237762cb9SSteven Rostedt #undef get_mcountsym 3341b402a2SSteven Rostedt #undef get_sym_str_and_relp 34c28d5077SSteven Rostedt #undef do_func 35412910cdSWu Zhangjin #undef Elf_Addr 36c28d5077SSteven Rostedt #undef Elf_Ehdr 37c28d5077SSteven Rostedt #undef Elf_Shdr 38c28d5077SSteven Rostedt #undef Elf_Rel 39c28d5077SSteven Rostedt #undef Elf_Rela 40c28d5077SSteven Rostedt #undef Elf_Sym 41c28d5077SSteven Rostedt #undef ELF_R_SYM 42a2d49358SJohn Reiser #undef Elf_r_sym 43c28d5077SSteven Rostedt #undef ELF_R_INFO 44a2d49358SJohn Reiser #undef Elf_r_info 45c28d5077SSteven Rostedt #undef ELF_ST_BIND 469905ce8aSRabin Vincent #undef ELF_ST_TYPE 47a2d49358SJohn Reiser #undef fn_ELF_R_SYM 48a2d49358SJohn Reiser #undef fn_ELF_R_INFO 49c28d5077SSteven Rostedt #undef uint_t 50c28d5077SSteven Rostedt #undef _w 51c28d5077SSteven Rostedt #undef _align 52c28d5077SSteven Rostedt #undef _size 53c28d5077SSteven Rostedt 54c28d5077SSteven Rostedt #ifdef RECORD_MCOUNT_64 55c28d5077SSteven Rostedt # define append_func append64 56c28d5077SSteven Rostedt # define sift_rel_mcount sift64_rel_mcount 57ffd618faSSteven Rostedt # define nop_mcount nop_mcount_64 58c28d5077SSteven Rostedt # define find_secsym_ndx find64_secsym_ndx 59c28d5077SSteven Rostedt # define __has_rel_mcount __has64_rel_mcount 60c28d5077SSteven Rostedt # define has_rel_mcount has64_rel_mcount 61c28d5077SSteven Rostedt # define tot_relsize tot64_relsize 6241b402a2SSteven Rostedt # define get_sym_str_and_relp get_sym_str_and_relp_64 63c28d5077SSteven Rostedt # define do_func do64 6437762cb9SSteven Rostedt # define get_mcountsym get_mcountsym_64 65412910cdSWu Zhangjin # define is_fake_mcount is_fake_mcount64 66412910cdSWu Zhangjin # define fn_is_fake_mcount fn_is_fake_mcount64 67412910cdSWu Zhangjin # define MIPS_is_fake_mcount MIPS64_is_fake_mcount 6807d8b595SMartin Schwidefsky # define mcount_adjust mcount_adjust_64 69412910cdSWu Zhangjin # define Elf_Addr Elf64_Addr 70c28d5077SSteven Rostedt # define Elf_Ehdr Elf64_Ehdr 71c28d5077SSteven Rostedt # define Elf_Shdr Elf64_Shdr 72c28d5077SSteven Rostedt # define Elf_Rel Elf64_Rel 73c28d5077SSteven Rostedt # define Elf_Rela Elf64_Rela 74c28d5077SSteven Rostedt # define Elf_Sym Elf64_Sym 75c28d5077SSteven Rostedt # define ELF_R_SYM ELF64_R_SYM 76a2d49358SJohn Reiser # define Elf_r_sym Elf64_r_sym 77c28d5077SSteven Rostedt # define ELF_R_INFO ELF64_R_INFO 78a2d49358SJohn Reiser # define Elf_r_info Elf64_r_info 79c28d5077SSteven Rostedt # define ELF_ST_BIND ELF64_ST_BIND 809905ce8aSRabin Vincent # define ELF_ST_TYPE ELF64_ST_TYPE 81a2d49358SJohn Reiser # define fn_ELF_R_SYM fn_ELF64_R_SYM 82a2d49358SJohn Reiser # define fn_ELF_R_INFO fn_ELF64_R_INFO 83c28d5077SSteven Rostedt # define uint_t uint64_t 84c28d5077SSteven Rostedt # define _w w8 85c28d5077SSteven Rostedt # define _align 7u 86c28d5077SSteven Rostedt # define _size 8 87c28d5077SSteven Rostedt #else 88c28d5077SSteven Rostedt # define append_func append32 89c28d5077SSteven Rostedt # define sift_rel_mcount sift32_rel_mcount 90ffd618faSSteven Rostedt # define nop_mcount nop_mcount_32 91c28d5077SSteven Rostedt # define find_secsym_ndx find32_secsym_ndx 92c28d5077SSteven Rostedt # define __has_rel_mcount __has32_rel_mcount 93c28d5077SSteven Rostedt # define has_rel_mcount has32_rel_mcount 94c28d5077SSteven Rostedt # define tot_relsize tot32_relsize 9541b402a2SSteven Rostedt # define get_sym_str_and_relp get_sym_str_and_relp_32 96c28d5077SSteven Rostedt # define do_func do32 9737762cb9SSteven Rostedt # define get_mcountsym get_mcountsym_32 98412910cdSWu Zhangjin # define is_fake_mcount is_fake_mcount32 99412910cdSWu Zhangjin # define fn_is_fake_mcount fn_is_fake_mcount32 100412910cdSWu Zhangjin # define MIPS_is_fake_mcount MIPS32_is_fake_mcount 10107d8b595SMartin Schwidefsky # define mcount_adjust mcount_adjust_32 102412910cdSWu Zhangjin # define Elf_Addr Elf32_Addr 103c28d5077SSteven Rostedt # define Elf_Ehdr Elf32_Ehdr 104c28d5077SSteven Rostedt # define Elf_Shdr Elf32_Shdr 105c28d5077SSteven Rostedt # define Elf_Rel Elf32_Rel 106c28d5077SSteven Rostedt # define Elf_Rela Elf32_Rela 107c28d5077SSteven Rostedt # define Elf_Sym Elf32_Sym 108c28d5077SSteven Rostedt # define ELF_R_SYM ELF32_R_SYM 109a2d49358SJohn Reiser # define Elf_r_sym Elf32_r_sym 110c28d5077SSteven Rostedt # define ELF_R_INFO ELF32_R_INFO 111a2d49358SJohn Reiser # define Elf_r_info Elf32_r_info 112c28d5077SSteven Rostedt # define ELF_ST_BIND ELF32_ST_BIND 1139905ce8aSRabin Vincent # define ELF_ST_TYPE ELF32_ST_TYPE 114a2d49358SJohn Reiser # define fn_ELF_R_SYM fn_ELF32_R_SYM 115a2d49358SJohn Reiser # define fn_ELF_R_INFO fn_ELF32_R_INFO 116c28d5077SSteven Rostedt # define uint_t uint32_t 117c28d5077SSteven Rostedt # define _w w 118c28d5077SSteven Rostedt # define _align 3u 119c28d5077SSteven Rostedt # define _size 4 120c28d5077SSteven Rostedt #endif 121c28d5077SSteven Rostedt 122412910cdSWu Zhangjin /* Functions and pointers that do_file() may override for specific e_machine. */ 123412910cdSWu Zhangjin static int fn_is_fake_mcount(Elf_Rel const *rp) 124412910cdSWu Zhangjin { 125412910cdSWu Zhangjin return 0; 126412910cdSWu Zhangjin } 127412910cdSWu Zhangjin static int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount; 128412910cdSWu Zhangjin 129a2d49358SJohn Reiser static uint_t fn_ELF_R_SYM(Elf_Rel const *rp) 130a2d49358SJohn Reiser { 131a2d49358SJohn Reiser return ELF_R_SYM(_w(rp->r_info)); 132a2d49358SJohn Reiser } 133a2d49358SJohn Reiser static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM; 134a2d49358SJohn Reiser 135a2d49358SJohn Reiser static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type) 136a2d49358SJohn Reiser { 137e63233f7SJohn Reiser rp->r_info = _w(ELF_R_INFO(sym, type)); 138a2d49358SJohn Reiser } 139a2d49358SJohn Reiser static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; 140a2d49358SJohn Reiser 14107d8b595SMartin Schwidefsky static int mcount_adjust = 0; 14207d8b595SMartin Schwidefsky 143412910cdSWu Zhangjin /* 144412910cdSWu Zhangjin * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st 145412910cdSWu Zhangjin * _mcount symbol is needed for dynamic function tracer, with it, to disable 146412910cdSWu Zhangjin * tracing(ftrace_make_nop), the instruction in the position is replaced with 147412910cdSWu Zhangjin * the "b label" instruction, to enable tracing(ftrace_make_call), replace the 148412910cdSWu Zhangjin * instruction back. So, here, we set the 2nd one as fake and filter it. 149412910cdSWu Zhangjin * 150412910cdSWu Zhangjin * c: 3c030000 lui v1,0x0 <--> b label 151412910cdSWu Zhangjin * c: R_MIPS_HI16 _mcount 152412910cdSWu Zhangjin * c: R_MIPS_NONE *ABS* 153412910cdSWu Zhangjin * c: R_MIPS_NONE *ABS* 154412910cdSWu Zhangjin * 10: 64630000 daddiu v1,v1,0 155412910cdSWu Zhangjin * 10: R_MIPS_LO16 _mcount 156412910cdSWu Zhangjin * 10: R_MIPS_NONE *ABS* 157412910cdSWu Zhangjin * 10: R_MIPS_NONE *ABS* 158412910cdSWu Zhangjin * 14: 03e0082d move at,ra 159412910cdSWu Zhangjin * 18: 0060f809 jalr v1 160412910cdSWu Zhangjin * label: 161412910cdSWu Zhangjin */ 162412910cdSWu Zhangjin #define MIPS_FAKEMCOUNT_OFFSET 4 163412910cdSWu Zhangjin 164412910cdSWu Zhangjin static int MIPS_is_fake_mcount(Elf_Rel const *rp) 165412910cdSWu Zhangjin { 16691ad11d7SAlex Smith static Elf_Addr old_r_offset = ~(Elf_Addr)0; 167412910cdSWu Zhangjin Elf_Addr current_r_offset = _w(rp->r_offset); 168412910cdSWu Zhangjin int is_fake; 169412910cdSWu Zhangjin 17091ad11d7SAlex Smith is_fake = (old_r_offset != ~(Elf_Addr)0) && 171412910cdSWu Zhangjin (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET); 172412910cdSWu Zhangjin old_r_offset = current_r_offset; 173412910cdSWu Zhangjin 174412910cdSWu Zhangjin return is_fake; 175412910cdSWu Zhangjin } 176a2d49358SJohn Reiser 177c28d5077SSteven Rostedt /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ 178c28d5077SSteven Rostedt static void append_func(Elf_Ehdr *const ehdr, 179c28d5077SSteven Rostedt Elf_Shdr *const shstr, 180c28d5077SSteven Rostedt uint_t const *const mloc0, 181c28d5077SSteven Rostedt uint_t const *const mlocp, 182c28d5077SSteven Rostedt Elf_Rel const *const mrel0, 183c28d5077SSteven Rostedt Elf_Rel const *const mrelp, 184c28d5077SSteven Rostedt unsigned int const rel_entsize, 185c28d5077SSteven Rostedt unsigned int const symsec_sh_link) 186c28d5077SSteven Rostedt { 187c28d5077SSteven Rostedt /* Begin constructing output file */ 188c28d5077SSteven Rostedt Elf_Shdr mcsec; 189c28d5077SSteven Rostedt char const *mc_name = (sizeof(Elf_Rela) == rel_entsize) 190c28d5077SSteven Rostedt ? ".rela__mcount_loc" 191c28d5077SSteven Rostedt : ".rel__mcount_loc"; 192c28d5077SSteven Rostedt unsigned const old_shnum = w2(ehdr->e_shnum); 193c28d5077SSteven Rostedt uint_t const old_shoff = _w(ehdr->e_shoff); 194c28d5077SSteven Rostedt uint_t const old_shstr_sh_size = _w(shstr->sh_size); 195c28d5077SSteven Rostedt uint_t const old_shstr_sh_offset = _w(shstr->sh_offset); 196c28d5077SSteven Rostedt uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size); 197c28d5077SSteven Rostedt uint_t new_e_shoff; 198c28d5077SSteven Rostedt 199c28d5077SSteven Rostedt shstr->sh_size = _w(t); 200c28d5077SSteven Rostedt shstr->sh_offset = _w(sb.st_size); 201c28d5077SSteven Rostedt t += sb.st_size; 202c28d5077SSteven Rostedt t += (_align & -t); /* word-byte align */ 203c28d5077SSteven Rostedt new_e_shoff = t; 204c28d5077SSteven Rostedt 205c28d5077SSteven Rostedt /* body for new shstrtab */ 206c28d5077SSteven Rostedt ulseek(fd_map, sb.st_size, SEEK_SET); 207c28d5077SSteven Rostedt uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size); 208c28d5077SSteven Rostedt uwrite(fd_map, mc_name, 1 + strlen(mc_name)); 209c28d5077SSteven Rostedt 210c28d5077SSteven Rostedt /* old(modified) Elf_Shdr table, word-byte aligned */ 211c28d5077SSteven Rostedt ulseek(fd_map, t, SEEK_SET); 212c28d5077SSteven Rostedt t += sizeof(Elf_Shdr) * old_shnum; 213c28d5077SSteven Rostedt uwrite(fd_map, old_shoff + (void *)ehdr, 214c28d5077SSteven Rostedt sizeof(Elf_Shdr) * old_shnum); 215c28d5077SSteven Rostedt 216c28d5077SSteven Rostedt /* new sections __mcount_loc and .rel__mcount_loc */ 217c28d5077SSteven Rostedt t += 2*sizeof(mcsec); 218c28d5077SSteven Rostedt mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel") 219c28d5077SSteven Rostedt + old_shstr_sh_size); 220c28d5077SSteven Rostedt mcsec.sh_type = w(SHT_PROGBITS); 221c28d5077SSteven Rostedt mcsec.sh_flags = _w(SHF_ALLOC); 222c28d5077SSteven Rostedt mcsec.sh_addr = 0; 223c28d5077SSteven Rostedt mcsec.sh_offset = _w(t); 224c28d5077SSteven Rostedt mcsec.sh_size = _w((void *)mlocp - (void *)mloc0); 225c28d5077SSteven Rostedt mcsec.sh_link = 0; 226c28d5077SSteven Rostedt mcsec.sh_info = 0; 227c28d5077SSteven Rostedt mcsec.sh_addralign = _w(_size); 228c28d5077SSteven Rostedt mcsec.sh_entsize = _w(_size); 229c28d5077SSteven Rostedt uwrite(fd_map, &mcsec, sizeof(mcsec)); 230c28d5077SSteven Rostedt 231c28d5077SSteven Rostedt mcsec.sh_name = w(old_shstr_sh_size); 232c28d5077SSteven Rostedt mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize) 233c28d5077SSteven Rostedt ? w(SHT_RELA) 234c28d5077SSteven Rostedt : w(SHT_REL); 235c28d5077SSteven Rostedt mcsec.sh_flags = 0; 236c28d5077SSteven Rostedt mcsec.sh_addr = 0; 237c28d5077SSteven Rostedt mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t); 238c28d5077SSteven Rostedt mcsec.sh_size = _w((void *)mrelp - (void *)mrel0); 239c28d5077SSteven Rostedt mcsec.sh_link = w(symsec_sh_link); 240c28d5077SSteven Rostedt mcsec.sh_info = w(old_shnum); 241c28d5077SSteven Rostedt mcsec.sh_addralign = _w(_size); 242c28d5077SSteven Rostedt mcsec.sh_entsize = _w(rel_entsize); 243c28d5077SSteven Rostedt uwrite(fd_map, &mcsec, sizeof(mcsec)); 244c28d5077SSteven Rostedt 245c28d5077SSteven Rostedt uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0); 246c28d5077SSteven Rostedt uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0); 247c28d5077SSteven Rostedt 248c28d5077SSteven Rostedt ehdr->e_shoff = _w(new_e_shoff); 249c28d5077SSteven Rostedt ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */ 250c28d5077SSteven Rostedt ulseek(fd_map, 0, SEEK_SET); 251c28d5077SSteven Rostedt uwrite(fd_map, ehdr, sizeof(*ehdr)); 252c28d5077SSteven Rostedt } 253c28d5077SSteven Rostedt 25437762cb9SSteven Rostedt static unsigned get_mcountsym(Elf_Sym const *const sym0, 25537762cb9SSteven Rostedt Elf_Rel const *relp, 25637762cb9SSteven Rostedt char const *const str0) 25737762cb9SSteven Rostedt { 25837762cb9SSteven Rostedt unsigned mcountsym = 0; 25937762cb9SSteven Rostedt 26037762cb9SSteven Rostedt Elf_Sym const *const symp = 26137762cb9SSteven Rostedt &sym0[Elf_r_sym(relp)]; 26237762cb9SSteven Rostedt char const *symname = &str0[w(symp->st_name)]; 26337762cb9SSteven Rostedt char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; 26448bb5dc6SSteven Rostedt char const *fentry = "__fentry__"; 26537762cb9SSteven Rostedt 26637762cb9SSteven Rostedt if (symname[0] == '.') 26737762cb9SSteven Rostedt ++symname; /* ppc64 hack */ 26837762cb9SSteven Rostedt if (strcmp(mcount, symname) == 0 || 26948bb5dc6SSteven Rostedt (altmcount && strcmp(altmcount, symname) == 0) || 27048bb5dc6SSteven Rostedt (strcmp(fentry, symname) == 0)) 27137762cb9SSteven Rostedt mcountsym = Elf_r_sym(relp); 27237762cb9SSteven Rostedt 27337762cb9SSteven Rostedt return mcountsym; 27437762cb9SSteven Rostedt } 27537762cb9SSteven Rostedt 27641b402a2SSteven Rostedt static void get_sym_str_and_relp(Elf_Shdr const *const relhdr, 27741b402a2SSteven Rostedt Elf_Ehdr const *const ehdr, 27841b402a2SSteven Rostedt Elf_Sym const **sym0, 27941b402a2SSteven Rostedt char const **str0, 28041b402a2SSteven Rostedt Elf_Rel const **relp) 28141b402a2SSteven Rostedt { 28241b402a2SSteven Rostedt Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) 28341b402a2SSteven Rostedt + (void *)ehdr); 28441b402a2SSteven Rostedt unsigned const symsec_sh_link = w(relhdr->sh_link); 28541b402a2SSteven Rostedt Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; 28641b402a2SSteven Rostedt Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; 28741b402a2SSteven Rostedt Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset) 28841b402a2SSteven Rostedt + (void *)ehdr); 28941b402a2SSteven Rostedt 29041b402a2SSteven Rostedt *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) 29141b402a2SSteven Rostedt + (void *)ehdr); 29241b402a2SSteven Rostedt 29341b402a2SSteven Rostedt *str0 = (char const *)(_w(strsec->sh_offset) 29441b402a2SSteven Rostedt + (void *)ehdr); 29541b402a2SSteven Rostedt 29641b402a2SSteven Rostedt *relp = rel0; 29741b402a2SSteven Rostedt } 29841b402a2SSteven Rostedt 299c28d5077SSteven Rostedt /* 300c28d5077SSteven Rostedt * Look at the relocations in order to find the calls to mcount. 301c28d5077SSteven Rostedt * Accumulate the section offsets that are found, and their relocation info, 302c28d5077SSteven Rostedt * onto the end of the existing arrays. 303c28d5077SSteven Rostedt */ 304c28d5077SSteven Rostedt static uint_t *sift_rel_mcount(uint_t *mlocp, 305c28d5077SSteven Rostedt unsigned const offbase, 306c28d5077SSteven Rostedt Elf_Rel **const mrelpp, 307c28d5077SSteven Rostedt Elf_Shdr const *const relhdr, 308c28d5077SSteven Rostedt Elf_Ehdr const *const ehdr, 309c28d5077SSteven Rostedt unsigned const recsym, 310c28d5077SSteven Rostedt uint_t const recval, 311c28d5077SSteven Rostedt unsigned const reltype) 312c28d5077SSteven Rostedt { 313c28d5077SSteven Rostedt uint_t *const mloc0 = mlocp; 314c28d5077SSteven Rostedt Elf_Rel *mrelp = *mrelpp; 31541b402a2SSteven Rostedt Elf_Sym const *sym0; 31641b402a2SSteven Rostedt char const *str0; 31741b402a2SSteven Rostedt Elf_Rel const *relp; 318c28d5077SSteven Rostedt unsigned rel_entsize = _w(relhdr->sh_entsize); 319c28d5077SSteven Rostedt unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; 320c28d5077SSteven Rostedt unsigned mcountsym = 0; 321c28d5077SSteven Rostedt unsigned t; 322c28d5077SSteven Rostedt 32341b402a2SSteven Rostedt get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp); 32441b402a2SSteven Rostedt 325c28d5077SSteven Rostedt for (t = nrel; t; --t) { 32637762cb9SSteven Rostedt if (!mcountsym) 32737762cb9SSteven Rostedt mcountsym = get_mcountsym(sym0, relp, str0); 328c28d5077SSteven Rostedt 329412910cdSWu Zhangjin if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { 33007d8b595SMartin Schwidefsky uint_t const addend = 33107d8b595SMartin Schwidefsky _w(_w(relp->r_offset) - recval + mcount_adjust); 332c28d5077SSteven Rostedt mrelp->r_offset = _w(offbase 333c28d5077SSteven Rostedt + ((void *)mlocp - (void *)mloc0)); 334a2d49358SJohn Reiser Elf_r_info(mrelp, recsym, reltype); 335dd5477ffSSteven Rostedt if (rel_entsize == sizeof(Elf_Rela)) { 336c28d5077SSteven Rostedt ((Elf_Rela *)mrelp)->r_addend = addend; 337c28d5077SSteven Rostedt *mlocp++ = 0; 338c28d5077SSteven Rostedt } else 339c28d5077SSteven Rostedt *mlocp++ = addend; 340c28d5077SSteven Rostedt 341c28d5077SSteven Rostedt mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp); 342c28d5077SSteven Rostedt } 343c28d5077SSteven Rostedt relp = (Elf_Rel const *)(rel_entsize + (void *)relp); 344c28d5077SSteven Rostedt } 345c28d5077SSteven Rostedt *mrelpp = mrelp; 346c28d5077SSteven Rostedt return mlocp; 347c28d5077SSteven Rostedt } 348c28d5077SSteven Rostedt 349ffd618faSSteven Rostedt /* 350ffd618faSSteven Rostedt * Read the relocation table again, but this time its called on sections 351ffd618faSSteven Rostedt * that are not going to be traced. The mcount calls here will be converted 352ffd618faSSteven Rostedt * into nops. 353ffd618faSSteven Rostedt */ 354ffd618faSSteven Rostedt static void nop_mcount(Elf_Shdr const *const relhdr, 355dfad3d59SSteven Rostedt Elf_Ehdr const *const ehdr, 356dfad3d59SSteven Rostedt const char *const txtname) 357ffd618faSSteven Rostedt { 358ffd618faSSteven Rostedt Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) 359ffd618faSSteven Rostedt + (void *)ehdr); 36041b402a2SSteven Rostedt Elf_Sym const *sym0; 36141b402a2SSteven Rostedt char const *str0; 36241b402a2SSteven Rostedt Elf_Rel const *relp; 36341b402a2SSteven Rostedt Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)]; 364ffd618faSSteven Rostedt unsigned rel_entsize = _w(relhdr->sh_entsize); 365ffd618faSSteven Rostedt unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; 366ffd618faSSteven Rostedt unsigned mcountsym = 0; 367ffd618faSSteven Rostedt unsigned t; 368dfad3d59SSteven Rostedt int once = 0; 369ffd618faSSteven Rostedt 37041b402a2SSteven Rostedt get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp); 37141b402a2SSteven Rostedt 372ffd618faSSteven Rostedt for (t = nrel; t; --t) { 373ffd618faSSteven Rostedt int ret = -1; 374ffd618faSSteven Rostedt 37537762cb9SSteven Rostedt if (!mcountsym) 37637762cb9SSteven Rostedt mcountsym = get_mcountsym(sym0, relp, str0); 377ffd618faSSteven Rostedt 378dfad3d59SSteven Rostedt if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { 379dfad3d59SSteven Rostedt if (make_nop) 380c84da8b9Slibin ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset)); 381dfad3d59SSteven Rostedt if (warn_on_notrace_sect && !once) { 382dfad3d59SSteven Rostedt printf("Section %s has mcount callers being ignored\n", 383dfad3d59SSteven Rostedt txtname); 384dfad3d59SSteven Rostedt once = 1; 385dfad3d59SSteven Rostedt /* just warn? */ 386dfad3d59SSteven Rostedt if (!make_nop) 387dfad3d59SSteven Rostedt return; 388dfad3d59SSteven Rostedt } 389dfad3d59SSteven Rostedt } 390ffd618faSSteven Rostedt 391ffd618faSSteven Rostedt /* 392ffd618faSSteven Rostedt * If we successfully removed the mcount, mark the relocation 393ffd618faSSteven Rostedt * as a nop (don't do anything with it). 394ffd618faSSteven Rostedt */ 395ffd618faSSteven Rostedt if (!ret) { 396ffd618faSSteven Rostedt Elf_Rel rel; 397ffd618faSSteven Rostedt rel = *(Elf_Rel *)relp; 398ffd618faSSteven Rostedt Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop); 399ffd618faSSteven Rostedt ulseek(fd_map, (void *)relp - (void *)ehdr, SEEK_SET); 400ffd618faSSteven Rostedt uwrite(fd_map, &rel, sizeof(rel)); 401ffd618faSSteven Rostedt } 402ffd618faSSteven Rostedt relp = (Elf_Rel const *)(rel_entsize + (void *)relp); 403ffd618faSSteven Rostedt } 404ffd618faSSteven Rostedt } 405ffd618faSSteven Rostedt 406c28d5077SSteven Rostedt 407c28d5077SSteven Rostedt /* 408c28d5077SSteven Rostedt * Find a symbol in the given section, to be used as the base for relocating 409c28d5077SSteven Rostedt * the table of offsets of calls to mcount. A local or global symbol suffices, 410c28d5077SSteven Rostedt * but avoid a Weak symbol because it may be overridden; the change in value 411c28d5077SSteven Rostedt * would invalidate the relocations of the offsets of the calls to mcount. 412c28d5077SSteven Rostedt * Often the found symbol will be the unnamed local symbol generated by 413c28d5077SSteven Rostedt * GNU 'as' for the start of each section. For example: 414c28d5077SSteven Rostedt * Num: Value Size Type Bind Vis Ndx Name 415c28d5077SSteven Rostedt * 2: 00000000 0 SECTION LOCAL DEFAULT 1 416c28d5077SSteven Rostedt */ 417c28d5077SSteven Rostedt static unsigned find_secsym_ndx(unsigned const txtndx, 418c28d5077SSteven Rostedt char const *const txtname, 419c28d5077SSteven Rostedt uint_t *const recvalp, 420c28d5077SSteven Rostedt Elf_Shdr const *const symhdr, 421c28d5077SSteven Rostedt Elf_Ehdr const *const ehdr) 422c28d5077SSteven Rostedt { 423c28d5077SSteven Rostedt Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset) 424c28d5077SSteven Rostedt + (void *)ehdr); 425c28d5077SSteven Rostedt unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize); 426c28d5077SSteven Rostedt Elf_Sym const *symp; 427c28d5077SSteven Rostedt unsigned t; 428c28d5077SSteven Rostedt 429c28d5077SSteven Rostedt for (symp = sym0, t = nsym; t; --t, ++symp) { 430c28d5077SSteven Rostedt unsigned int const st_bind = ELF_ST_BIND(symp->st_info); 431c28d5077SSteven Rostedt 432c28d5077SSteven Rostedt if (txtndx == w2(symp->st_shndx) 433c28d5077SSteven Rostedt /* avoid STB_WEAK */ 434c28d5077SSteven Rostedt && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) { 4359905ce8aSRabin Vincent /* function symbols on ARM have quirks, avoid them */ 4369905ce8aSRabin Vincent if (w2(ehdr->e_machine) == EM_ARM 4379905ce8aSRabin Vincent && ELF_ST_TYPE(symp->st_info) == STT_FUNC) 4389905ce8aSRabin Vincent continue; 4399905ce8aSRabin Vincent 440c28d5077SSteven Rostedt *recvalp = _w(symp->st_value); 441c28d5077SSteven Rostedt return symp - sym0; 442c28d5077SSteven Rostedt } 443c28d5077SSteven Rostedt } 444c28d5077SSteven Rostedt fprintf(stderr, "Cannot find symbol for section %d: %s.\n", 445c28d5077SSteven Rostedt txtndx, txtname); 446c28d5077SSteven Rostedt fail_file(); 447c28d5077SSteven Rostedt } 448c28d5077SSteven Rostedt 449c28d5077SSteven Rostedt 450c28d5077SSteven Rostedt /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */ 451c28d5077SSteven Rostedt static char const * 452c28d5077SSteven Rostedt __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ 453c28d5077SSteven Rostedt Elf_Shdr const *const shdr0, 454c28d5077SSteven Rostedt char const *const shstrtab, 455c28d5077SSteven Rostedt char const *const fname) 456c28d5077SSteven Rostedt { 457c28d5077SSteven Rostedt /* .sh_info depends on .sh_type == SHT_REL[,A] */ 458c28d5077SSteven Rostedt Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)]; 459c28d5077SSteven Rostedt char const *const txtname = &shstrtab[w(txthdr->sh_name)]; 460c28d5077SSteven Rostedt 461dd5477ffSSteven Rostedt if (strcmp("__mcount_loc", txtname) == 0) { 462c28d5077SSteven Rostedt fprintf(stderr, "warning: __mcount_loc already exists: %s\n", 463c28d5077SSteven Rostedt fname); 464c28d5077SSteven Rostedt succeed_file(); 465c28d5077SSteven Rostedt } 466dd5477ffSSteven Rostedt if (w(txthdr->sh_type) != SHT_PROGBITS || 4672e885057SDavid Daney !(_w(txthdr->sh_flags) & SHF_EXECINSTR)) 468c28d5077SSteven Rostedt return NULL; 469c28d5077SSteven Rostedt return txtname; 470c28d5077SSteven Rostedt } 471c28d5077SSteven Rostedt 472c28d5077SSteven Rostedt static char const *has_rel_mcount(Elf_Shdr const *const relhdr, 473c28d5077SSteven Rostedt Elf_Shdr const *const shdr0, 474c28d5077SSteven Rostedt char const *const shstrtab, 475c28d5077SSteven Rostedt char const *const fname) 476c28d5077SSteven Rostedt { 477dd5477ffSSteven Rostedt if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA) 478c28d5077SSteven Rostedt return NULL; 479c28d5077SSteven Rostedt return __has_rel_mcount(relhdr, shdr0, shstrtab, fname); 480c28d5077SSteven Rostedt } 481c28d5077SSteven Rostedt 482c28d5077SSteven Rostedt 483c28d5077SSteven Rostedt static unsigned tot_relsize(Elf_Shdr const *const shdr0, 484c28d5077SSteven Rostedt unsigned nhdr, 485c28d5077SSteven Rostedt const char *const shstrtab, 486c28d5077SSteven Rostedt const char *const fname) 487c28d5077SSteven Rostedt { 488c28d5077SSteven Rostedt unsigned totrelsz = 0; 489c28d5077SSteven Rostedt Elf_Shdr const *shdrp = shdr0; 490ffd618faSSteven Rostedt char const *txtname; 491c28d5077SSteven Rostedt 492c28d5077SSteven Rostedt for (; nhdr; --nhdr, ++shdrp) { 493ffd618faSSteven Rostedt txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname); 494ffd618faSSteven Rostedt if (txtname && is_mcounted_section_name(txtname)) 495c28d5077SSteven Rostedt totrelsz += _w(shdrp->sh_size); 496c28d5077SSteven Rostedt } 497c28d5077SSteven Rostedt return totrelsz; 498c28d5077SSteven Rostedt } 499c28d5077SSteven Rostedt 500c28d5077SSteven Rostedt 501c28d5077SSteven Rostedt /* Overall supervision for Elf32 ET_REL file. */ 502c28d5077SSteven Rostedt static void 503c28d5077SSteven Rostedt do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) 504c28d5077SSteven Rostedt { 505c28d5077SSteven Rostedt Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) 506c28d5077SSteven Rostedt + (void *)ehdr); 507c28d5077SSteven Rostedt unsigned const nhdr = w2(ehdr->e_shnum); 508c28d5077SSteven Rostedt Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)]; 509c28d5077SSteven Rostedt char const *const shstrtab = (char const *)(_w(shstr->sh_offset) 510c28d5077SSteven Rostedt + (void *)ehdr); 511c28d5077SSteven Rostedt 512c28d5077SSteven Rostedt Elf_Shdr const *relhdr; 513c28d5077SSteven Rostedt unsigned k; 514c28d5077SSteven Rostedt 515c28d5077SSteven Rostedt /* Upper bound on space: assume all relevant relocs are for mcount. */ 516c28d5077SSteven Rostedt unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname); 517c28d5077SSteven Rostedt Elf_Rel *const mrel0 = umalloc(totrelsz); 518c28d5077SSteven Rostedt Elf_Rel * mrelp = mrel0; 519c28d5077SSteven Rostedt 520c28d5077SSteven Rostedt /* 2*sizeof(address) <= sizeof(Elf_Rel) */ 521c28d5077SSteven Rostedt uint_t *const mloc0 = umalloc(totrelsz>>1); 522c28d5077SSteven Rostedt uint_t * mlocp = mloc0; 523c28d5077SSteven Rostedt 524c28d5077SSteven Rostedt unsigned rel_entsize = 0; 525c28d5077SSteven Rostedt unsigned symsec_sh_link = 0; 526c28d5077SSteven Rostedt 527c28d5077SSteven Rostedt for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { 528c28d5077SSteven Rostedt char const *const txtname = has_rel_mcount(relhdr, shdr0, 529c28d5077SSteven Rostedt shstrtab, fname); 530ffd618faSSteven Rostedt if (txtname && is_mcounted_section_name(txtname)) { 531c28d5077SSteven Rostedt uint_t recval = 0; 532c28d5077SSteven Rostedt unsigned const recsym = find_secsym_ndx( 533c28d5077SSteven Rostedt w(relhdr->sh_info), txtname, &recval, 534c28d5077SSteven Rostedt &shdr0[symsec_sh_link = w(relhdr->sh_link)], 535c28d5077SSteven Rostedt ehdr); 536c28d5077SSteven Rostedt 537c28d5077SSteven Rostedt rel_entsize = _w(relhdr->sh_entsize); 538c28d5077SSteven Rostedt mlocp = sift_rel_mcount(mlocp, 539c28d5077SSteven Rostedt (void *)mlocp - (void *)mloc0, &mrelp, 540c28d5077SSteven Rostedt relhdr, ehdr, recsym, recval, reltype); 541dfad3d59SSteven Rostedt } else if (txtname && (warn_on_notrace_sect || make_nop)) { 542ffd618faSSteven Rostedt /* 543ffd618faSSteven Rostedt * This section is ignored by ftrace, but still 544ffd618faSSteven Rostedt * has mcount calls. Convert them to nops now. 545ffd618faSSteven Rostedt */ 546dfad3d59SSteven Rostedt nop_mcount(relhdr, ehdr, txtname); 547c28d5077SSteven Rostedt } 548c28d5077SSteven Rostedt } 549c28d5077SSteven Rostedt if (mloc0 != mlocp) { 550c28d5077SSteven Rostedt append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp, 551c28d5077SSteven Rostedt rel_entsize, symsec_sh_link); 552c28d5077SSteven Rostedt } 553c28d5077SSteven Rostedt free(mrel0); 554c28d5077SSteven Rostedt free(mloc0); 555c28d5077SSteven Rostedt } 556