aboutsummaryrefslogtreecommitdiff
path: root/scripts/recordmcount.h
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/recordmcount.h')
-rw-r--r--scripts/recordmcount.h86
1 files changed, 81 insertions, 5 deletions
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index 7f39d0943d2..58e933a2054 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -19,20 +19,28 @@
* 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
#undef Elf_Rela
#undef Elf_Sym
#undef ELF_R_SYM
+#undef Elf_r_sym
#undef ELF_R_INFO
+#undef Elf_r_info
#undef ELF_ST_BIND
+#undef fn_ELF_R_SYM
+#undef fn_ELF_R_INFO
#undef uint_t
#undef _w
#undef _align
@@ -46,14 +54,22 @@
# 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
# define Elf_Rela Elf64_Rela
# define Elf_Sym Elf64_Sym
# define ELF_R_SYM ELF64_R_SYM
+# define Elf_r_sym Elf64_r_sym
# define ELF_R_INFO ELF64_R_INFO
+# define Elf_r_info Elf64_r_info
# define ELF_ST_BIND ELF64_ST_BIND
+# define fn_ELF_R_SYM fn_ELF64_R_SYM
+# define fn_ELF_R_INFO fn_ELF64_R_INFO
# define uint_t uint64_t
# define _w w8
# define _align 7u
@@ -66,20 +82,81 @@
# 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
# define Elf_Rela Elf32_Rela
# define Elf_Sym Elf32_Sym
# define ELF_R_SYM ELF32_R_SYM
+# define Elf_r_sym Elf32_r_sym
# define ELF_R_INFO ELF32_R_INFO
+# define Elf_r_info Elf32_r_info
# define ELF_ST_BIND ELF32_ST_BIND
+# define fn_ELF_R_SYM fn_ELF32_R_SYM
+# define fn_ELF_R_INFO fn_ELF32_R_INFO
# define uint_t uint32_t
# define _w w
# define _align 3u
# define _size 4
#endif
+/* 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));
+}
+static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM;
+
+static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
+{
+ rp->r_info = ELF_R_INFO(sym, 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,
Elf_Shdr *const shstr,
@@ -157,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,
@@ -197,22 +273,22 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
for (t = nrel; t; --t) {
if (!mcountsym) {
Elf_Sym const *const symp =
- &sym0[ELF_R_SYM(_w(relp->r_info))];
+ &sym0[Elf_r_sym(relp)];
char const *symname = &str0[w(symp->st_name)];
if ('.' == symname[0])
++symname; /* ppc64 hack */
if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"),
symname))
- mcountsym = ELF_R_SYM(_w(relp->r_info));
+ mcountsym = Elf_r_sym(relp);
}
- if (mcountsym == ELF_R_SYM(_w(relp->r_info))) {
+ 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
+ ((void *)mlocp - (void *)mloc0));
- mrelp->r_info = _w(ELF_R_INFO(recsym, reltype));
+ Elf_r_info(mrelp, recsym, reltype);
if (sizeof(Elf_Rela) == rel_entsize) {
((Elf_Rela *)mrelp)->r_addend = addend;
*mlocp++ = 0;