diff options
Diffstat (limited to 'scripts/recordmcount.h')
| -rw-r--r-- | scripts/recordmcount.h | 86 | 
1 files changed, 81 insertions, 5 deletions
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 7f39d0943d2d..58e933a20544 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;  | 
