18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * recordmcount.h
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This code was taken out of recordmcount.c written by
68c2ecf20Sopenharmony_ci * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * The original code had the same algorithms for both 32bit
98c2ecf20Sopenharmony_ci * and 64bit ELF files, but the code was duplicated to support
108c2ecf20Sopenharmony_ci * the difference in structures that were used. This
118c2ecf20Sopenharmony_ci * file creates a macro of everything that is different between
128c2ecf20Sopenharmony_ci * the 64 and 32 bit code, such that by including this header
138c2ecf20Sopenharmony_ci * twice we can create both sets of functions by including this
148c2ecf20Sopenharmony_ci * header once with RECORD_MCOUNT_64 undefined, and again with
158c2ecf20Sopenharmony_ci * it defined.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * This conversion to macros was done by:
188c2ecf20Sopenharmony_ci * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci#undef append_func
218c2ecf20Sopenharmony_ci#undef is_fake_mcount
228c2ecf20Sopenharmony_ci#undef fn_is_fake_mcount
238c2ecf20Sopenharmony_ci#undef MIPS_is_fake_mcount
248c2ecf20Sopenharmony_ci#undef mcount_adjust
258c2ecf20Sopenharmony_ci#undef sift_rel_mcount
268c2ecf20Sopenharmony_ci#undef nop_mcount
278c2ecf20Sopenharmony_ci#undef find_secsym_ndx
288c2ecf20Sopenharmony_ci#undef __has_rel_mcount
298c2ecf20Sopenharmony_ci#undef has_rel_mcount
308c2ecf20Sopenharmony_ci#undef tot_relsize
318c2ecf20Sopenharmony_ci#undef get_mcountsym
328c2ecf20Sopenharmony_ci#undef find_symtab
338c2ecf20Sopenharmony_ci#undef get_shnum
348c2ecf20Sopenharmony_ci#undef set_shnum
358c2ecf20Sopenharmony_ci#undef get_shstrndx
368c2ecf20Sopenharmony_ci#undef get_symindex
378c2ecf20Sopenharmony_ci#undef get_sym_str_and_relp
388c2ecf20Sopenharmony_ci#undef do_func
398c2ecf20Sopenharmony_ci#undef Elf_Addr
408c2ecf20Sopenharmony_ci#undef Elf_Ehdr
418c2ecf20Sopenharmony_ci#undef Elf_Shdr
428c2ecf20Sopenharmony_ci#undef Elf_Rel
438c2ecf20Sopenharmony_ci#undef Elf_Rela
448c2ecf20Sopenharmony_ci#undef Elf_Sym
458c2ecf20Sopenharmony_ci#undef ELF_R_SYM
468c2ecf20Sopenharmony_ci#undef Elf_r_sym
478c2ecf20Sopenharmony_ci#undef ELF_R_INFO
488c2ecf20Sopenharmony_ci#undef Elf_r_info
498c2ecf20Sopenharmony_ci#undef ELF_ST_BIND
508c2ecf20Sopenharmony_ci#undef ELF_ST_TYPE
518c2ecf20Sopenharmony_ci#undef fn_ELF_R_SYM
528c2ecf20Sopenharmony_ci#undef fn_ELF_R_INFO
538c2ecf20Sopenharmony_ci#undef uint_t
548c2ecf20Sopenharmony_ci#undef _w
558c2ecf20Sopenharmony_ci#undef _align
568c2ecf20Sopenharmony_ci#undef _size
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#ifdef RECORD_MCOUNT_64
598c2ecf20Sopenharmony_ci# define append_func		append64
608c2ecf20Sopenharmony_ci# define sift_rel_mcount	sift64_rel_mcount
618c2ecf20Sopenharmony_ci# define nop_mcount		nop_mcount_64
628c2ecf20Sopenharmony_ci# define find_secsym_ndx	find64_secsym_ndx
638c2ecf20Sopenharmony_ci# define __has_rel_mcount	__has64_rel_mcount
648c2ecf20Sopenharmony_ci# define has_rel_mcount		has64_rel_mcount
658c2ecf20Sopenharmony_ci# define tot_relsize		tot64_relsize
668c2ecf20Sopenharmony_ci# define find_symtab		find_symtab64
678c2ecf20Sopenharmony_ci# define get_shnum		get_shnum64
688c2ecf20Sopenharmony_ci# define set_shnum		set_shnum64
698c2ecf20Sopenharmony_ci# define get_shstrndx		get_shstrndx64
708c2ecf20Sopenharmony_ci# define get_symindex		get_symindex64
718c2ecf20Sopenharmony_ci# define get_sym_str_and_relp	get_sym_str_and_relp_64
728c2ecf20Sopenharmony_ci# define do_func		do64
738c2ecf20Sopenharmony_ci# define get_mcountsym		get_mcountsym_64
748c2ecf20Sopenharmony_ci# define is_fake_mcount		is_fake_mcount64
758c2ecf20Sopenharmony_ci# define fn_is_fake_mcount	fn_is_fake_mcount64
768c2ecf20Sopenharmony_ci# define MIPS_is_fake_mcount	MIPS64_is_fake_mcount
778c2ecf20Sopenharmony_ci# define mcount_adjust		mcount_adjust_64
788c2ecf20Sopenharmony_ci# define Elf_Addr		Elf64_Addr
798c2ecf20Sopenharmony_ci# define Elf_Ehdr		Elf64_Ehdr
808c2ecf20Sopenharmony_ci# define Elf_Shdr		Elf64_Shdr
818c2ecf20Sopenharmony_ci# define Elf_Rel		Elf64_Rel
828c2ecf20Sopenharmony_ci# define Elf_Rela		Elf64_Rela
838c2ecf20Sopenharmony_ci# define Elf_Sym		Elf64_Sym
848c2ecf20Sopenharmony_ci# define ELF_R_SYM		ELF64_R_SYM
858c2ecf20Sopenharmony_ci# define Elf_r_sym		Elf64_r_sym
868c2ecf20Sopenharmony_ci# define ELF_R_INFO		ELF64_R_INFO
878c2ecf20Sopenharmony_ci# define Elf_r_info		Elf64_r_info
888c2ecf20Sopenharmony_ci# define ELF_ST_BIND		ELF64_ST_BIND
898c2ecf20Sopenharmony_ci# define ELF_ST_TYPE		ELF64_ST_TYPE
908c2ecf20Sopenharmony_ci# define fn_ELF_R_SYM		fn_ELF64_R_SYM
918c2ecf20Sopenharmony_ci# define fn_ELF_R_INFO		fn_ELF64_R_INFO
928c2ecf20Sopenharmony_ci# define uint_t			uint64_t
938c2ecf20Sopenharmony_ci# define _w			w8
948c2ecf20Sopenharmony_ci# define _align			7u
958c2ecf20Sopenharmony_ci# define _size			8
968c2ecf20Sopenharmony_ci#else
978c2ecf20Sopenharmony_ci# define append_func		append32
988c2ecf20Sopenharmony_ci# define sift_rel_mcount	sift32_rel_mcount
998c2ecf20Sopenharmony_ci# define nop_mcount		nop_mcount_32
1008c2ecf20Sopenharmony_ci# define find_secsym_ndx	find32_secsym_ndx
1018c2ecf20Sopenharmony_ci# define __has_rel_mcount	__has32_rel_mcount
1028c2ecf20Sopenharmony_ci# define has_rel_mcount		has32_rel_mcount
1038c2ecf20Sopenharmony_ci# define tot_relsize		tot32_relsize
1048c2ecf20Sopenharmony_ci# define find_symtab		find_symtab32
1058c2ecf20Sopenharmony_ci# define get_shnum		get_shnum32
1068c2ecf20Sopenharmony_ci# define set_shnum		set_shnum32
1078c2ecf20Sopenharmony_ci# define get_shstrndx		get_shstrndx32
1088c2ecf20Sopenharmony_ci# define get_symindex		get_symindex32
1098c2ecf20Sopenharmony_ci# define get_sym_str_and_relp	get_sym_str_and_relp_32
1108c2ecf20Sopenharmony_ci# define do_func		do32
1118c2ecf20Sopenharmony_ci# define get_mcountsym		get_mcountsym_32
1128c2ecf20Sopenharmony_ci# define is_fake_mcount		is_fake_mcount32
1138c2ecf20Sopenharmony_ci# define fn_is_fake_mcount	fn_is_fake_mcount32
1148c2ecf20Sopenharmony_ci# define MIPS_is_fake_mcount	MIPS32_is_fake_mcount
1158c2ecf20Sopenharmony_ci# define mcount_adjust		mcount_adjust_32
1168c2ecf20Sopenharmony_ci# define Elf_Addr		Elf32_Addr
1178c2ecf20Sopenharmony_ci# define Elf_Ehdr		Elf32_Ehdr
1188c2ecf20Sopenharmony_ci# define Elf_Shdr		Elf32_Shdr
1198c2ecf20Sopenharmony_ci# define Elf_Rel		Elf32_Rel
1208c2ecf20Sopenharmony_ci# define Elf_Rela		Elf32_Rela
1218c2ecf20Sopenharmony_ci# define Elf_Sym		Elf32_Sym
1228c2ecf20Sopenharmony_ci# define ELF_R_SYM		ELF32_R_SYM
1238c2ecf20Sopenharmony_ci# define Elf_r_sym		Elf32_r_sym
1248c2ecf20Sopenharmony_ci# define ELF_R_INFO		ELF32_R_INFO
1258c2ecf20Sopenharmony_ci# define Elf_r_info		Elf32_r_info
1268c2ecf20Sopenharmony_ci# define ELF_ST_BIND		ELF32_ST_BIND
1278c2ecf20Sopenharmony_ci# define ELF_ST_TYPE		ELF32_ST_TYPE
1288c2ecf20Sopenharmony_ci# define fn_ELF_R_SYM		fn_ELF32_R_SYM
1298c2ecf20Sopenharmony_ci# define fn_ELF_R_INFO		fn_ELF32_R_INFO
1308c2ecf20Sopenharmony_ci# define uint_t			uint32_t
1318c2ecf20Sopenharmony_ci# define _w			w
1328c2ecf20Sopenharmony_ci# define _align			3u
1338c2ecf20Sopenharmony_ci# define _size			4
1348c2ecf20Sopenharmony_ci#endif
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* Functions and pointers that do_file() may override for specific e_machine. */
1378c2ecf20Sopenharmony_cistatic int fn_is_fake_mcount(Elf_Rel const *rp)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	return 0;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_cistatic int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic uint_t fn_ELF_R_SYM(Elf_Rel const *rp)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	return ELF_R_SYM(_w(rp->r_info));
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_cistatic uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	rp->r_info = _w(ELF_R_INFO(sym, type));
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_cistatic void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic int mcount_adjust = 0;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/*
1588c2ecf20Sopenharmony_ci * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st
1598c2ecf20Sopenharmony_ci * _mcount symbol is needed for dynamic function tracer, with it, to disable
1608c2ecf20Sopenharmony_ci * tracing(ftrace_make_nop), the instruction in the position is replaced with
1618c2ecf20Sopenharmony_ci * the "b label" instruction, to enable tracing(ftrace_make_call), replace the
1628c2ecf20Sopenharmony_ci * instruction back. So, here, we set the 2nd one as fake and filter it.
1638c2ecf20Sopenharmony_ci *
1648c2ecf20Sopenharmony_ci * c:	3c030000	lui	v1,0x0		<-->	b	label
1658c2ecf20Sopenharmony_ci *		c: R_MIPS_HI16	_mcount
1668c2ecf20Sopenharmony_ci *		c: R_MIPS_NONE	*ABS*
1678c2ecf20Sopenharmony_ci *		c: R_MIPS_NONE	*ABS*
1688c2ecf20Sopenharmony_ci * 10:	64630000	daddiu	v1,v1,0
1698c2ecf20Sopenharmony_ci *		10: R_MIPS_LO16	_mcount
1708c2ecf20Sopenharmony_ci *		10: R_MIPS_NONE	*ABS*
1718c2ecf20Sopenharmony_ci *		10: R_MIPS_NONE	*ABS*
1728c2ecf20Sopenharmony_ci * 14:	03e0082d	move	at,ra
1738c2ecf20Sopenharmony_ci * 18:	0060f809	jalr	v1
1748c2ecf20Sopenharmony_ci * label:
1758c2ecf20Sopenharmony_ci */
1768c2ecf20Sopenharmony_ci#define MIPS_FAKEMCOUNT_OFFSET	4
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int MIPS_is_fake_mcount(Elf_Rel const *rp)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	static Elf_Addr old_r_offset = ~(Elf_Addr)0;
1818c2ecf20Sopenharmony_ci	Elf_Addr current_r_offset = _w(rp->r_offset);
1828c2ecf20Sopenharmony_ci	int is_fake;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	is_fake = (old_r_offset != ~(Elf_Addr)0) &&
1858c2ecf20Sopenharmony_ci		(current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
1868c2ecf20Sopenharmony_ci	old_r_offset = current_r_offset;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return is_fake;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic unsigned int get_symindex(Elf_Sym const *sym, Elf32_Word const *symtab,
1928c2ecf20Sopenharmony_ci				 Elf32_Word const *symtab_shndx)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	unsigned long offset;
1958c2ecf20Sopenharmony_ci	unsigned short shndx = w2(sym->st_shndx);
1968c2ecf20Sopenharmony_ci	int index;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (shndx > SHN_UNDEF && shndx < SHN_LORESERVE)
1998c2ecf20Sopenharmony_ci		return shndx;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (shndx == SHN_XINDEX) {
2028c2ecf20Sopenharmony_ci		offset = (unsigned long)sym - (unsigned long)symtab;
2038c2ecf20Sopenharmony_ci		index = offset / sizeof(*sym);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		return w(symtab_shndx[index]);
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	return 0;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	if (shdr0 && !ehdr->e_shnum)
2148c2ecf20Sopenharmony_ci		return w(shdr0->sh_size);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	return w2(ehdr->e_shnum);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic void set_shnum(Elf_Ehdr *ehdr, Elf_Shdr *shdr0, unsigned int new_shnum)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	if (new_shnum >= SHN_LORESERVE) {
2228c2ecf20Sopenharmony_ci		ehdr->e_shnum = 0;
2238c2ecf20Sopenharmony_ci		shdr0->sh_size = w(new_shnum);
2248c2ecf20Sopenharmony_ci	} else
2258c2ecf20Sopenharmony_ci		ehdr->e_shnum = w2(new_shnum);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int get_shstrndx(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	if (ehdr->e_shstrndx != SHN_XINDEX)
2318c2ecf20Sopenharmony_ci		return w2(ehdr->e_shstrndx);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return w(shdr0->sh_link);
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic void find_symtab(Elf_Ehdr *const ehdr, Elf_Shdr const *shdr0,
2378c2ecf20Sopenharmony_ci			unsigned const nhdr, Elf32_Word **symtab,
2388c2ecf20Sopenharmony_ci			Elf32_Word **symtab_shndx)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	Elf_Shdr const *relhdr;
2418c2ecf20Sopenharmony_ci	unsigned k;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	*symtab = NULL;
2448c2ecf20Sopenharmony_ci	*symtab_shndx = NULL;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
2478c2ecf20Sopenharmony_ci		if (relhdr->sh_type == SHT_SYMTAB)
2488c2ecf20Sopenharmony_ci			*symtab = (void *)ehdr + relhdr->sh_offset;
2498c2ecf20Sopenharmony_ci		else if (relhdr->sh_type == SHT_SYMTAB_SHNDX)
2508c2ecf20Sopenharmony_ci			*symtab_shndx = (void *)ehdr + relhdr->sh_offset;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		if (*symtab && *symtab_shndx)
2538c2ecf20Sopenharmony_ci			break;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
2588c2ecf20Sopenharmony_cistatic int append_func(Elf_Ehdr *const ehdr,
2598c2ecf20Sopenharmony_ci			Elf_Shdr *const shstr,
2608c2ecf20Sopenharmony_ci			uint_t const *const mloc0,
2618c2ecf20Sopenharmony_ci			uint_t const *const mlocp,
2628c2ecf20Sopenharmony_ci			Elf_Rel const *const mrel0,
2638c2ecf20Sopenharmony_ci			Elf_Rel const *const mrelp,
2648c2ecf20Sopenharmony_ci			unsigned int const rel_entsize,
2658c2ecf20Sopenharmony_ci			unsigned int const symsec_sh_link)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	/* Begin constructing output file */
2688c2ecf20Sopenharmony_ci	Elf_Shdr mcsec;
2698c2ecf20Sopenharmony_ci	char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
2708c2ecf20Sopenharmony_ci		? ".rela__mcount_loc"
2718c2ecf20Sopenharmony_ci		:  ".rel__mcount_loc";
2728c2ecf20Sopenharmony_ci	uint_t const old_shoff = _w(ehdr->e_shoff);
2738c2ecf20Sopenharmony_ci	uint_t const old_shstr_sh_size   = _w(shstr->sh_size);
2748c2ecf20Sopenharmony_ci	uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
2758c2ecf20Sopenharmony_ci	Elf_Shdr *const shdr0 = (Elf_Shdr *)(old_shoff + (void *)ehdr);
2768c2ecf20Sopenharmony_ci	unsigned int const old_shnum = get_shnum(ehdr, shdr0);
2778c2ecf20Sopenharmony_ci	unsigned int const new_shnum = 2 + old_shnum; /* {.rel,}__mcount_loc */
2788c2ecf20Sopenharmony_ci	uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
2798c2ecf20Sopenharmony_ci	uint_t new_e_shoff;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	shstr->sh_size = _w(t);
2828c2ecf20Sopenharmony_ci	shstr->sh_offset = _w(sb.st_size);
2838c2ecf20Sopenharmony_ci	t += sb.st_size;
2848c2ecf20Sopenharmony_ci	t += (_align & -t);  /* word-byte align */
2858c2ecf20Sopenharmony_ci	new_e_shoff = t;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	set_shnum(ehdr, shdr0, new_shnum);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* body for new shstrtab */
2908c2ecf20Sopenharmony_ci	if (ulseek(sb.st_size, SEEK_SET) < 0)
2918c2ecf20Sopenharmony_ci		return -1;
2928c2ecf20Sopenharmony_ci	if (uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size) < 0)
2938c2ecf20Sopenharmony_ci		return -1;
2948c2ecf20Sopenharmony_ci	if (uwrite(mc_name, 1 + strlen(mc_name)) < 0)
2958c2ecf20Sopenharmony_ci		return -1;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/* old(modified) Elf_Shdr table, word-byte aligned */
2988c2ecf20Sopenharmony_ci	if (ulseek(t, SEEK_SET) < 0)
2998c2ecf20Sopenharmony_ci		return -1;
3008c2ecf20Sopenharmony_ci	t += sizeof(Elf_Shdr) * old_shnum;
3018c2ecf20Sopenharmony_ci	if (uwrite(old_shoff + (void *)ehdr,
3028c2ecf20Sopenharmony_ci	       sizeof(Elf_Shdr) * old_shnum) < 0)
3038c2ecf20Sopenharmony_ci		return -1;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* new sections __mcount_loc and .rel__mcount_loc */
3068c2ecf20Sopenharmony_ci	t += 2*sizeof(mcsec);
3078c2ecf20Sopenharmony_ci	mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
3088c2ecf20Sopenharmony_ci		+ old_shstr_sh_size);
3098c2ecf20Sopenharmony_ci	mcsec.sh_type = w(SHT_PROGBITS);
3108c2ecf20Sopenharmony_ci	mcsec.sh_flags = _w(SHF_ALLOC);
3118c2ecf20Sopenharmony_ci	mcsec.sh_addr = 0;
3128c2ecf20Sopenharmony_ci	mcsec.sh_offset = _w(t);
3138c2ecf20Sopenharmony_ci	mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
3148c2ecf20Sopenharmony_ci	mcsec.sh_link = 0;
3158c2ecf20Sopenharmony_ci	mcsec.sh_info = 0;
3168c2ecf20Sopenharmony_ci	mcsec.sh_addralign = _w(_size);
3178c2ecf20Sopenharmony_ci	mcsec.sh_entsize = _w(_size);
3188c2ecf20Sopenharmony_ci	if (uwrite(&mcsec, sizeof(mcsec)) < 0)
3198c2ecf20Sopenharmony_ci		return -1;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	mcsec.sh_name = w(old_shstr_sh_size);
3228c2ecf20Sopenharmony_ci	mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
3238c2ecf20Sopenharmony_ci		? w(SHT_RELA)
3248c2ecf20Sopenharmony_ci		: w(SHT_REL);
3258c2ecf20Sopenharmony_ci	mcsec.sh_flags = 0;
3268c2ecf20Sopenharmony_ci	mcsec.sh_addr = 0;
3278c2ecf20Sopenharmony_ci	mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
3288c2ecf20Sopenharmony_ci	mcsec.sh_size   = _w((void *)mrelp - (void *)mrel0);
3298c2ecf20Sopenharmony_ci	mcsec.sh_link = w(symsec_sh_link);
3308c2ecf20Sopenharmony_ci	mcsec.sh_info = w(old_shnum);
3318c2ecf20Sopenharmony_ci	mcsec.sh_addralign = _w(_size);
3328c2ecf20Sopenharmony_ci	mcsec.sh_entsize = _w(rel_entsize);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (uwrite(&mcsec, sizeof(mcsec)) < 0)
3358c2ecf20Sopenharmony_ci		return -1;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0)
3388c2ecf20Sopenharmony_ci		return -1;
3398c2ecf20Sopenharmony_ci	if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0)
3408c2ecf20Sopenharmony_ci		return -1;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	ehdr->e_shoff = _w(new_e_shoff);
3438c2ecf20Sopenharmony_ci	if (ulseek(0, SEEK_SET) < 0)
3448c2ecf20Sopenharmony_ci		return -1;
3458c2ecf20Sopenharmony_ci	if (uwrite(ehdr, sizeof(*ehdr)) < 0)
3468c2ecf20Sopenharmony_ci		return -1;
3478c2ecf20Sopenharmony_ci	return 0;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic unsigned get_mcountsym(Elf_Sym const *const sym0,
3518c2ecf20Sopenharmony_ci			      Elf_Rel const *relp,
3528c2ecf20Sopenharmony_ci			      char const *const str0)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	unsigned mcountsym = 0;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	Elf_Sym const *const symp =
3578c2ecf20Sopenharmony_ci		&sym0[Elf_r_sym(relp)];
3588c2ecf20Sopenharmony_ci	char const *symname = &str0[w(symp->st_name)];
3598c2ecf20Sopenharmony_ci	char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
3608c2ecf20Sopenharmony_ci	char const *fentry = "__fentry__";
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (symname[0] == '.')
3638c2ecf20Sopenharmony_ci		++symname;  /* ppc64 hack */
3648c2ecf20Sopenharmony_ci	if (strcmp(mcount, symname) == 0 ||
3658c2ecf20Sopenharmony_ci	    (altmcount && strcmp(altmcount, symname) == 0) ||
3668c2ecf20Sopenharmony_ci	    (strcmp(fentry, symname) == 0))
3678c2ecf20Sopenharmony_ci		mcountsym = Elf_r_sym(relp);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return mcountsym;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
3738c2ecf20Sopenharmony_ci				 Elf_Ehdr const *const ehdr,
3748c2ecf20Sopenharmony_ci				 Elf_Sym const **sym0,
3758c2ecf20Sopenharmony_ci				 char const **str0,
3768c2ecf20Sopenharmony_ci				 Elf_Rel const **relp)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
3798c2ecf20Sopenharmony_ci		+ (void *)ehdr);
3808c2ecf20Sopenharmony_ci	unsigned const symsec_sh_link = w(relhdr->sh_link);
3818c2ecf20Sopenharmony_ci	Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
3828c2ecf20Sopenharmony_ci	Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
3838c2ecf20Sopenharmony_ci	Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
3848c2ecf20Sopenharmony_ci		+ (void *)ehdr);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	*sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
3878c2ecf20Sopenharmony_ci				  + (void *)ehdr);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	*str0 = (char const *)(_w(strsec->sh_offset)
3908c2ecf20Sopenharmony_ci			       + (void *)ehdr);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	*relp = rel0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci/*
3968c2ecf20Sopenharmony_ci * Look at the relocations in order to find the calls to mcount.
3978c2ecf20Sopenharmony_ci * Accumulate the section offsets that are found, and their relocation info,
3988c2ecf20Sopenharmony_ci * onto the end of the existing arrays.
3998c2ecf20Sopenharmony_ci */
4008c2ecf20Sopenharmony_cistatic uint_t *sift_rel_mcount(uint_t *mlocp,
4018c2ecf20Sopenharmony_ci			       unsigned const offbase,
4028c2ecf20Sopenharmony_ci			       Elf_Rel **const mrelpp,
4038c2ecf20Sopenharmony_ci			       Elf_Shdr const *const relhdr,
4048c2ecf20Sopenharmony_ci			       Elf_Ehdr const *const ehdr,
4058c2ecf20Sopenharmony_ci			       unsigned const recsym,
4068c2ecf20Sopenharmony_ci			       uint_t const recval,
4078c2ecf20Sopenharmony_ci			       unsigned const reltype)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	uint_t *const mloc0 = mlocp;
4108c2ecf20Sopenharmony_ci	Elf_Rel *mrelp = *mrelpp;
4118c2ecf20Sopenharmony_ci	Elf_Sym const *sym0;
4128c2ecf20Sopenharmony_ci	char const *str0;
4138c2ecf20Sopenharmony_ci	Elf_Rel const *relp;
4148c2ecf20Sopenharmony_ci	unsigned rel_entsize = _w(relhdr->sh_entsize);
4158c2ecf20Sopenharmony_ci	unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
4168c2ecf20Sopenharmony_ci	unsigned mcountsym = 0;
4178c2ecf20Sopenharmony_ci	unsigned t;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	for (t = nrel; t; --t) {
4228c2ecf20Sopenharmony_ci		if (!mcountsym)
4238c2ecf20Sopenharmony_ci			mcountsym = get_mcountsym(sym0, relp, str0);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci		if (mcountsym && mcountsym == Elf_r_sym(relp) &&
4268c2ecf20Sopenharmony_ci				!is_fake_mcount(relp)) {
4278c2ecf20Sopenharmony_ci			uint_t const addend =
4288c2ecf20Sopenharmony_ci				_w(_w(relp->r_offset) - recval + mcount_adjust);
4298c2ecf20Sopenharmony_ci			mrelp->r_offset = _w(offbase
4308c2ecf20Sopenharmony_ci				+ ((void *)mlocp - (void *)mloc0));
4318c2ecf20Sopenharmony_ci			Elf_r_info(mrelp, recsym, reltype);
4328c2ecf20Sopenharmony_ci			if (rel_entsize == sizeof(Elf_Rela)) {
4338c2ecf20Sopenharmony_ci				((Elf_Rela *)mrelp)->r_addend = addend;
4348c2ecf20Sopenharmony_ci				*mlocp++ = 0;
4358c2ecf20Sopenharmony_ci			} else
4368c2ecf20Sopenharmony_ci				*mlocp++ = addend;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci			mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
4398c2ecf20Sopenharmony_ci		}
4408c2ecf20Sopenharmony_ci		relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci	*mrelpp = mrelp;
4438c2ecf20Sopenharmony_ci	return mlocp;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci/*
4478c2ecf20Sopenharmony_ci * Read the relocation table again, but this time its called on sections
4488c2ecf20Sopenharmony_ci * that are not going to be traced. The mcount calls here will be converted
4498c2ecf20Sopenharmony_ci * into nops.
4508c2ecf20Sopenharmony_ci */
4518c2ecf20Sopenharmony_cistatic int nop_mcount(Elf_Shdr const *const relhdr,
4528c2ecf20Sopenharmony_ci		      Elf_Ehdr const *const ehdr,
4538c2ecf20Sopenharmony_ci		      const char *const txtname)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
4568c2ecf20Sopenharmony_ci		+ (void *)ehdr);
4578c2ecf20Sopenharmony_ci	Elf_Sym const *sym0;
4588c2ecf20Sopenharmony_ci	char const *str0;
4598c2ecf20Sopenharmony_ci	Elf_Rel const *relp;
4608c2ecf20Sopenharmony_ci	Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
4618c2ecf20Sopenharmony_ci	unsigned rel_entsize = _w(relhdr->sh_entsize);
4628c2ecf20Sopenharmony_ci	unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
4638c2ecf20Sopenharmony_ci	unsigned mcountsym = 0;
4648c2ecf20Sopenharmony_ci	unsigned t;
4658c2ecf20Sopenharmony_ci	int once = 0;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	for (t = nrel; t; --t) {
4708c2ecf20Sopenharmony_ci		int ret = -1;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci		if (!mcountsym)
4738c2ecf20Sopenharmony_ci			mcountsym = get_mcountsym(sym0, relp, str0);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
4768c2ecf20Sopenharmony_ci			if (make_nop)
4778c2ecf20Sopenharmony_ci				ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
4788c2ecf20Sopenharmony_ci			if (warn_on_notrace_sect && !once) {
4798c2ecf20Sopenharmony_ci				printf("Section %s has mcount callers being ignored\n",
4808c2ecf20Sopenharmony_ci				       txtname);
4818c2ecf20Sopenharmony_ci				once = 1;
4828c2ecf20Sopenharmony_ci				/* just warn? */
4838c2ecf20Sopenharmony_ci				if (!make_nop)
4848c2ecf20Sopenharmony_ci					return 0;
4858c2ecf20Sopenharmony_ci			}
4868c2ecf20Sopenharmony_ci		}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci		/*
4898c2ecf20Sopenharmony_ci		 * If we successfully removed the mcount, mark the relocation
4908c2ecf20Sopenharmony_ci		 * as a nop (don't do anything with it).
4918c2ecf20Sopenharmony_ci		 */
4928c2ecf20Sopenharmony_ci		if (!ret) {
4938c2ecf20Sopenharmony_ci			Elf_Rel rel;
4948c2ecf20Sopenharmony_ci			rel = *(Elf_Rel *)relp;
4958c2ecf20Sopenharmony_ci			Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
4968c2ecf20Sopenharmony_ci			if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0)
4978c2ecf20Sopenharmony_ci				return -1;
4988c2ecf20Sopenharmony_ci			if (uwrite(&rel, sizeof(rel)) < 0)
4998c2ecf20Sopenharmony_ci				return -1;
5008c2ecf20Sopenharmony_ci		}
5018c2ecf20Sopenharmony_ci		relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci	return 0;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci/*
5078c2ecf20Sopenharmony_ci * Find a symbol in the given section, to be used as the base for relocating
5088c2ecf20Sopenharmony_ci * the table of offsets of calls to mcount.  A local or global symbol suffices,
5098c2ecf20Sopenharmony_ci * but avoid a Weak symbol because it may be overridden; the change in value
5108c2ecf20Sopenharmony_ci * would invalidate the relocations of the offsets of the calls to mcount.
5118c2ecf20Sopenharmony_ci * Often the found symbol will be the unnamed local symbol generated by
5128c2ecf20Sopenharmony_ci * GNU 'as' for the start of each section.  For example:
5138c2ecf20Sopenharmony_ci *    Num:    Value  Size Type    Bind   Vis      Ndx Name
5148c2ecf20Sopenharmony_ci *      2: 00000000     0 SECTION LOCAL  DEFAULT    1
5158c2ecf20Sopenharmony_ci */
5168c2ecf20Sopenharmony_cistatic int find_secsym_ndx(unsigned const txtndx,
5178c2ecf20Sopenharmony_ci				char const *const txtname,
5188c2ecf20Sopenharmony_ci				uint_t *const recvalp,
5198c2ecf20Sopenharmony_ci				unsigned int *sym_index,
5208c2ecf20Sopenharmony_ci				Elf_Shdr const *const symhdr,
5218c2ecf20Sopenharmony_ci				Elf32_Word const *symtab,
5228c2ecf20Sopenharmony_ci				Elf32_Word const *symtab_shndx,
5238c2ecf20Sopenharmony_ci				Elf_Ehdr const *const ehdr)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
5268c2ecf20Sopenharmony_ci		+ (void *)ehdr);
5278c2ecf20Sopenharmony_ci	unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
5288c2ecf20Sopenharmony_ci	Elf_Sym const *symp;
5298c2ecf20Sopenharmony_ci	unsigned t;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	for (symp = sym0, t = nsym; t; --t, ++symp) {
5328c2ecf20Sopenharmony_ci		unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci		if (txtndx == get_symindex(symp, symtab, symtab_shndx)
5358c2ecf20Sopenharmony_ci			/* avoid STB_WEAK */
5368c2ecf20Sopenharmony_ci		    && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
5378c2ecf20Sopenharmony_ci			/* function symbols on ARM have quirks, avoid them */
5388c2ecf20Sopenharmony_ci			if (w2(ehdr->e_machine) == EM_ARM
5398c2ecf20Sopenharmony_ci			    && ELF_ST_TYPE(symp->st_info) == STT_FUNC)
5408c2ecf20Sopenharmony_ci				continue;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci			*recvalp = _w(symp->st_value);
5438c2ecf20Sopenharmony_ci			*sym_index = symp - sym0;
5448c2ecf20Sopenharmony_ci			return 0;
5458c2ecf20Sopenharmony_ci		}
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
5488c2ecf20Sopenharmony_ci		txtndx, txtname);
5498c2ecf20Sopenharmony_ci	return -1;
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
5538c2ecf20Sopenharmony_cistatic char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
5548c2ecf20Sopenharmony_ci				     Elf_Shdr const *const shdr0,
5558c2ecf20Sopenharmony_ci				     char const *const shstrtab,
5568c2ecf20Sopenharmony_ci				     char const *const fname)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	/* .sh_info depends on .sh_type == SHT_REL[,A] */
5598c2ecf20Sopenharmony_ci	Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
5608c2ecf20Sopenharmony_ci	char const *const txtname = &shstrtab[w(txthdr->sh_name)];
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (strcmp("__mcount_loc", txtname) == 0) {
5638c2ecf20Sopenharmony_ci		fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
5648c2ecf20Sopenharmony_ci			fname);
5658c2ecf20Sopenharmony_ci		return already_has_rel_mcount;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci	if (w(txthdr->sh_type) != SHT_PROGBITS ||
5688c2ecf20Sopenharmony_ci	    !(_w(txthdr->sh_flags) & SHF_EXECINSTR))
5698c2ecf20Sopenharmony_ci		return NULL;
5708c2ecf20Sopenharmony_ci	return txtname;
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic char const *has_rel_mcount(Elf_Shdr const *const relhdr,
5748c2ecf20Sopenharmony_ci				  Elf_Shdr const *const shdr0,
5758c2ecf20Sopenharmony_ci				  char const *const shstrtab,
5768c2ecf20Sopenharmony_ci				  char const *const fname)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA)
5798c2ecf20Sopenharmony_ci		return NULL;
5808c2ecf20Sopenharmony_ci	return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic unsigned tot_relsize(Elf_Shdr const *const shdr0,
5858c2ecf20Sopenharmony_ci			    unsigned nhdr,
5868c2ecf20Sopenharmony_ci			    const char *const shstrtab,
5878c2ecf20Sopenharmony_ci			    const char *const fname)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	unsigned totrelsz = 0;
5908c2ecf20Sopenharmony_ci	Elf_Shdr const *shdrp = shdr0;
5918c2ecf20Sopenharmony_ci	char const *txtname;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	for (; nhdr; --nhdr, ++shdrp) {
5948c2ecf20Sopenharmony_ci		txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
5958c2ecf20Sopenharmony_ci		if (txtname == already_has_rel_mcount) {
5968c2ecf20Sopenharmony_ci			totrelsz = 0;
5978c2ecf20Sopenharmony_ci			break;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci		if (txtname && is_mcounted_section_name(txtname))
6008c2ecf20Sopenharmony_ci			totrelsz += _w(shdrp->sh_size);
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci	return totrelsz;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci/* Overall supervision for Elf32 ET_REL file. */
6068c2ecf20Sopenharmony_cistatic int do_func(Elf_Ehdr *const ehdr, char const *const fname,
6078c2ecf20Sopenharmony_ci		   unsigned const reltype)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
6108c2ecf20Sopenharmony_ci		+ (void *)ehdr);
6118c2ecf20Sopenharmony_ci	unsigned const nhdr = get_shnum(ehdr, shdr0);
6128c2ecf20Sopenharmony_ci	Elf_Shdr *const shstr = &shdr0[get_shstrndx(ehdr, shdr0)];
6138c2ecf20Sopenharmony_ci	char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
6148c2ecf20Sopenharmony_ci		+ (void *)ehdr);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	Elf_Shdr const *relhdr;
6178c2ecf20Sopenharmony_ci	unsigned k;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	Elf32_Word *symtab;
6208c2ecf20Sopenharmony_ci	Elf32_Word *symtab_shndx;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/* Upper bound on space: assume all relevant relocs are for mcount. */
6238c2ecf20Sopenharmony_ci	unsigned       totrelsz;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	Elf_Rel *      mrel0;
6268c2ecf20Sopenharmony_ci	Elf_Rel *      mrelp;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	uint_t *      mloc0;
6298c2ecf20Sopenharmony_ci	uint_t *      mlocp;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	unsigned rel_entsize = 0;
6328c2ecf20Sopenharmony_ci	unsigned symsec_sh_link = 0;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	int result = 0;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
6378c2ecf20Sopenharmony_ci	if (totrelsz == 0)
6388c2ecf20Sopenharmony_ci		return 0;
6398c2ecf20Sopenharmony_ci	mrel0 = umalloc(totrelsz);
6408c2ecf20Sopenharmony_ci	mrelp = mrel0;
6418c2ecf20Sopenharmony_ci	if (!mrel0)
6428c2ecf20Sopenharmony_ci		return -1;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	/* 2*sizeof(address) <= sizeof(Elf_Rel) */
6458c2ecf20Sopenharmony_ci	mloc0 = umalloc(totrelsz>>1);
6468c2ecf20Sopenharmony_ci	mlocp = mloc0;
6478c2ecf20Sopenharmony_ci	if (!mloc0) {
6488c2ecf20Sopenharmony_ci		free(mrel0);
6498c2ecf20Sopenharmony_ci		return -1;
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
6558c2ecf20Sopenharmony_ci		char const *const txtname = has_rel_mcount(relhdr, shdr0,
6568c2ecf20Sopenharmony_ci			shstrtab, fname);
6578c2ecf20Sopenharmony_ci		if (txtname == already_has_rel_mcount) {
6588c2ecf20Sopenharmony_ci			result = 0;
6598c2ecf20Sopenharmony_ci			file_updated = 0;
6608c2ecf20Sopenharmony_ci			goto out; /* Nothing to be done; don't append! */
6618c2ecf20Sopenharmony_ci		}
6628c2ecf20Sopenharmony_ci		if (txtname && is_mcounted_section_name(txtname)) {
6638c2ecf20Sopenharmony_ci			unsigned int recsym;
6648c2ecf20Sopenharmony_ci			uint_t recval = 0;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci			symsec_sh_link = w(relhdr->sh_link);
6678c2ecf20Sopenharmony_ci			result = find_secsym_ndx(w(relhdr->sh_info), txtname,
6688c2ecf20Sopenharmony_ci						&recval, &recsym,
6698c2ecf20Sopenharmony_ci						&shdr0[symsec_sh_link],
6708c2ecf20Sopenharmony_ci						symtab, symtab_shndx,
6718c2ecf20Sopenharmony_ci						ehdr);
6728c2ecf20Sopenharmony_ci			if (result)
6738c2ecf20Sopenharmony_ci				goto out;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci			rel_entsize = _w(relhdr->sh_entsize);
6768c2ecf20Sopenharmony_ci			mlocp = sift_rel_mcount(mlocp,
6778c2ecf20Sopenharmony_ci				(void *)mlocp - (void *)mloc0, &mrelp,
6788c2ecf20Sopenharmony_ci				relhdr, ehdr, recsym, recval, reltype);
6798c2ecf20Sopenharmony_ci		} else if (txtname && (warn_on_notrace_sect || make_nop)) {
6808c2ecf20Sopenharmony_ci			/*
6818c2ecf20Sopenharmony_ci			 * This section is ignored by ftrace, but still
6828c2ecf20Sopenharmony_ci			 * has mcount calls. Convert them to nops now.
6838c2ecf20Sopenharmony_ci			 */
6848c2ecf20Sopenharmony_ci			if (nop_mcount(relhdr, ehdr, txtname) < 0) {
6858c2ecf20Sopenharmony_ci				result = -1;
6868c2ecf20Sopenharmony_ci				goto out;
6878c2ecf20Sopenharmony_ci			}
6888c2ecf20Sopenharmony_ci		}
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci	if (!result && mloc0 != mlocp)
6918c2ecf20Sopenharmony_ci		result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
6928c2ecf20Sopenharmony_ci				     rel_entsize, symsec_sh_link);
6938c2ecf20Sopenharmony_ciout:
6948c2ecf20Sopenharmony_ci	free(mrel0);
6958c2ecf20Sopenharmony_ci	free(mloc0);
6968c2ecf20Sopenharmony_ci	return result;
6978c2ecf20Sopenharmony_ci}
698