diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 2d32b9ced20a..f2f32eee2c5b 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -325,8 +325,10 @@ do_file(char const *const fname) } if (EM_S390 == w2(ehdr->e_machine)) reltype = R_390_32; - if (EM_MIPS == w2(ehdr->e_machine)) + if (EM_MIPS == w2(ehdr->e_machine)) { reltype = R_MIPS_32; + is_fake_mcount32 = MIPS32_is_fake_mcount; + } do32(ehdr, fname, reltype); } break; case ELFCLASS64: { @@ -343,6 +345,7 @@ do_file(char const *const fname) reltype = R_MIPS_64; Elf64_r_sym = MIPS64_r_sym; Elf64_r_info = MIPS64_r_info; + is_fake_mcount64 = MIPS64_is_fake_mcount; } do64(ghdr, fname, reltype); } break; diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 190fd18dc853..58e933a20544 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -19,12 +19,16 @@ * Licensed under the GNU General Public License, version 2 (GPLv2). */ #undef append_func +#undef is_fake_mcount +#undef fn_is_fake_mcount +#undef MIPS_is_fake_mcount #undef sift_rel_mcount #undef find_secsym_ndx #undef __has_rel_mcount #undef has_rel_mcount #undef tot_relsize #undef do_func +#undef Elf_Addr #undef Elf_Ehdr #undef Elf_Shdr #undef Elf_Rel @@ -50,6 +54,10 @@ # define has_rel_mcount has64_rel_mcount # define tot_relsize tot64_relsize # define do_func do64 +# define is_fake_mcount is_fake_mcount64 +# define fn_is_fake_mcount fn_is_fake_mcount64 +# define MIPS_is_fake_mcount MIPS64_is_fake_mcount +# define Elf_Addr Elf64_Addr # define Elf_Ehdr Elf64_Ehdr # define Elf_Shdr Elf64_Shdr # define Elf_Rel Elf64_Rel @@ -74,6 +82,10 @@ # define has_rel_mcount has32_rel_mcount # define tot_relsize tot32_relsize # define do_func do32 +# define is_fake_mcount is_fake_mcount32 +# define fn_is_fake_mcount fn_is_fake_mcount32 +# define MIPS_is_fake_mcount MIPS32_is_fake_mcount +# define Elf_Addr Elf32_Addr # define Elf_Ehdr Elf32_Ehdr # define Elf_Shdr Elf32_Shdr # define Elf_Rel Elf32_Rel @@ -92,7 +104,13 @@ # define _size 4 #endif -/* Functions and pointers that 64-bit EM_MIPS can override. */ +/* Functions and pointers that do_file() may override for specific e_machine. */ +static int fn_is_fake_mcount(Elf_Rel const *rp) +{ + return 0; +} +static int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount; + static uint_t fn_ELF_R_SYM(Elf_Rel const *rp) { return ELF_R_SYM(_w(rp->r_info)); @@ -105,6 +123,39 @@ static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type) } static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; +/* + * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st + * _mcount symbol is needed for dynamic function tracer, with it, to disable + * tracing(ftrace_make_nop), the instruction in the position is replaced with + * the "b label" instruction, to enable tracing(ftrace_make_call), replace the + * instruction back. So, here, we set the 2nd one as fake and filter it. + * + * c: 3c030000 lui v1,0x0 <--> b label + * c: R_MIPS_HI16 _mcount + * c: R_MIPS_NONE *ABS* + * c: R_MIPS_NONE *ABS* + * 10: 64630000 daddiu v1,v1,0 + * 10: R_MIPS_LO16 _mcount + * 10: R_MIPS_NONE *ABS* + * 10: R_MIPS_NONE *ABS* + * 14: 03e0082d move at,ra + * 18: 0060f809 jalr v1 + * label: + */ +#define MIPS_FAKEMCOUNT_OFFSET 4 + +static int MIPS_is_fake_mcount(Elf_Rel const *rp) +{ + static Elf_Addr old_r_offset; + Elf_Addr current_r_offset = _w(rp->r_offset); + int is_fake; + + is_fake = old_r_offset && + (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET); + old_r_offset = current_r_offset; + + return is_fake; +} /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ static void append_func(Elf_Ehdr *const ehdr, @@ -183,7 +234,6 @@ static void append_func(Elf_Ehdr *const ehdr, uwrite(fd_map, ehdr, sizeof(*ehdr)); } - /* * Look at the relocations in order to find the calls to mcount. * Accumulate the section offsets that are found, and their relocation info, @@ -233,7 +283,7 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, mcountsym = Elf_r_sym(relp); } - if (mcountsym == Elf_r_sym(relp)) { + if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { uint_t const addend = _w(_w(relp->r_offset) - recval); mrelp->r_offset = _w(offbase