xref: /openbmc/linux/scripts/recordmcount.h (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
14317cf95SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2c28d5077SSteven Rostedt /*
3c28d5077SSteven Rostedt  * recordmcount.h
4c28d5077SSteven Rostedt  *
5c28d5077SSteven Rostedt  * This code was taken out of recordmcount.c written by
6c28d5077SSteven Rostedt  * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
7c28d5077SSteven Rostedt  *
8c28d5077SSteven Rostedt  * The original code had the same algorithms for both 32bit
9c28d5077SSteven Rostedt  * and 64bit ELF files, but the code was duplicated to support
10c28d5077SSteven Rostedt  * the difference in structures that were used. This
11c28d5077SSteven Rostedt  * file creates a macro of everything that is different between
12c28d5077SSteven Rostedt  * the 64 and 32 bit code, such that by including this header
13c28d5077SSteven Rostedt  * twice we can create both sets of functions by including this
14c28d5077SSteven Rostedt  * header once with RECORD_MCOUNT_64 undefined, and again with
15c28d5077SSteven Rostedt  * it defined.
16c28d5077SSteven Rostedt  *
17c28d5077SSteven Rostedt  * This conversion to macros was done by:
18c28d5077SSteven Rostedt  * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
19c28d5077SSteven Rostedt  */
20c28d5077SSteven Rostedt #undef append_func
21412910cdSWu Zhangjin #undef is_fake_mcount
22412910cdSWu Zhangjin #undef fn_is_fake_mcount
23412910cdSWu Zhangjin #undef MIPS_is_fake_mcount
2407d8b595SMartin Schwidefsky #undef mcount_adjust
25c28d5077SSteven Rostedt #undef sift_rel_mcount
26ffd618faSSteven Rostedt #undef nop_mcount
27c28d5077SSteven Rostedt #undef find_secsym_ndx
28c28d5077SSteven Rostedt #undef __has_rel_mcount
29c28d5077SSteven Rostedt #undef has_rel_mcount
30c28d5077SSteven Rostedt #undef tot_relsize
3137762cb9SSteven Rostedt #undef get_mcountsym
324ef57b21SSami Tolvanen #undef find_symtab
334ef57b21SSami Tolvanen #undef get_shnum
344ef57b21SSami Tolvanen #undef set_shnum
354ef57b21SSami Tolvanen #undef get_shstrndx
364ef57b21SSami Tolvanen #undef get_symindex
3741b402a2SSteven Rostedt #undef get_sym_str_and_relp
38c28d5077SSteven Rostedt #undef do_func
39412910cdSWu Zhangjin #undef Elf_Addr
40c28d5077SSteven Rostedt #undef Elf_Ehdr
41c28d5077SSteven Rostedt #undef Elf_Shdr
42c28d5077SSteven Rostedt #undef Elf_Rel
43c28d5077SSteven Rostedt #undef Elf_Rela
44c28d5077SSteven Rostedt #undef Elf_Sym
45c28d5077SSteven Rostedt #undef ELF_R_SYM
46a2d49358SJohn Reiser #undef Elf_r_sym
47c28d5077SSteven Rostedt #undef ELF_R_INFO
48a2d49358SJohn Reiser #undef Elf_r_info
49c28d5077SSteven Rostedt #undef ELF_ST_BIND
509905ce8aSRabin Vincent #undef ELF_ST_TYPE
51a2d49358SJohn Reiser #undef fn_ELF_R_SYM
52a2d49358SJohn Reiser #undef fn_ELF_R_INFO
53c28d5077SSteven Rostedt #undef uint_t
54c28d5077SSteven Rostedt #undef _w
55c28d5077SSteven Rostedt #undef _align
56c28d5077SSteven Rostedt #undef _size
57c28d5077SSteven Rostedt 
58c28d5077SSteven Rostedt #ifdef RECORD_MCOUNT_64
59c28d5077SSteven Rostedt # define append_func		append64
60c28d5077SSteven Rostedt # define sift_rel_mcount	sift64_rel_mcount
61ffd618faSSteven Rostedt # define nop_mcount		nop_mcount_64
62c28d5077SSteven Rostedt # define find_secsym_ndx	find64_secsym_ndx
63c28d5077SSteven Rostedt # define __has_rel_mcount	__has64_rel_mcount
64c28d5077SSteven Rostedt # define has_rel_mcount		has64_rel_mcount
65c28d5077SSteven Rostedt # define tot_relsize		tot64_relsize
664ef57b21SSami Tolvanen # define find_symtab		find_symtab64
674ef57b21SSami Tolvanen # define get_shnum		get_shnum64
684ef57b21SSami Tolvanen # define set_shnum		set_shnum64
694ef57b21SSami Tolvanen # define get_shstrndx		get_shstrndx64
704ef57b21SSami Tolvanen # define get_symindex		get_symindex64
7141b402a2SSteven Rostedt # define get_sym_str_and_relp	get_sym_str_and_relp_64
72c28d5077SSteven Rostedt # define do_func		do64
7337762cb9SSteven Rostedt # define get_mcountsym		get_mcountsym_64
74412910cdSWu Zhangjin # define is_fake_mcount		is_fake_mcount64
75412910cdSWu Zhangjin # define fn_is_fake_mcount	fn_is_fake_mcount64
76412910cdSWu Zhangjin # define MIPS_is_fake_mcount	MIPS64_is_fake_mcount
7707d8b595SMartin Schwidefsky # define mcount_adjust		mcount_adjust_64
78412910cdSWu Zhangjin # define Elf_Addr		Elf64_Addr
79c28d5077SSteven Rostedt # define Elf_Ehdr		Elf64_Ehdr
80c28d5077SSteven Rostedt # define Elf_Shdr		Elf64_Shdr
81c28d5077SSteven Rostedt # define Elf_Rel		Elf64_Rel
82c28d5077SSteven Rostedt # define Elf_Rela		Elf64_Rela
83c28d5077SSteven Rostedt # define Elf_Sym		Elf64_Sym
84c28d5077SSteven Rostedt # define ELF_R_SYM		ELF64_R_SYM
85a2d49358SJohn Reiser # define Elf_r_sym		Elf64_r_sym
86c28d5077SSteven Rostedt # define ELF_R_INFO		ELF64_R_INFO
87a2d49358SJohn Reiser # define Elf_r_info		Elf64_r_info
88c28d5077SSteven Rostedt # define ELF_ST_BIND		ELF64_ST_BIND
899905ce8aSRabin Vincent # define ELF_ST_TYPE		ELF64_ST_TYPE
90a2d49358SJohn Reiser # define fn_ELF_R_SYM		fn_ELF64_R_SYM
91a2d49358SJohn Reiser # define fn_ELF_R_INFO		fn_ELF64_R_INFO
92c28d5077SSteven Rostedt # define uint_t			uint64_t
93c28d5077SSteven Rostedt # define _w			w8
94c28d5077SSteven Rostedt # define _align			7u
95c28d5077SSteven Rostedt # define _size			8
96c28d5077SSteven Rostedt #else
97c28d5077SSteven Rostedt # define append_func		append32
98c28d5077SSteven Rostedt # define sift_rel_mcount	sift32_rel_mcount
99ffd618faSSteven Rostedt # define nop_mcount		nop_mcount_32
100c28d5077SSteven Rostedt # define find_secsym_ndx	find32_secsym_ndx
101c28d5077SSteven Rostedt # define __has_rel_mcount	__has32_rel_mcount
102c28d5077SSteven Rostedt # define has_rel_mcount		has32_rel_mcount
103c28d5077SSteven Rostedt # define tot_relsize		tot32_relsize
1044ef57b21SSami Tolvanen # define find_symtab		find_symtab32
1054ef57b21SSami Tolvanen # define get_shnum		get_shnum32
1064ef57b21SSami Tolvanen # define set_shnum		set_shnum32
1074ef57b21SSami Tolvanen # define get_shstrndx		get_shstrndx32
1084ef57b21SSami Tolvanen # define get_symindex		get_symindex32
10941b402a2SSteven Rostedt # define get_sym_str_and_relp	get_sym_str_and_relp_32
110c28d5077SSteven Rostedt # define do_func		do32
11137762cb9SSteven Rostedt # define get_mcountsym		get_mcountsym_32
112412910cdSWu Zhangjin # define is_fake_mcount		is_fake_mcount32
113412910cdSWu Zhangjin # define fn_is_fake_mcount	fn_is_fake_mcount32
114412910cdSWu Zhangjin # define MIPS_is_fake_mcount	MIPS32_is_fake_mcount
11507d8b595SMartin Schwidefsky # define mcount_adjust		mcount_adjust_32
116412910cdSWu Zhangjin # define Elf_Addr		Elf32_Addr
117c28d5077SSteven Rostedt # define Elf_Ehdr		Elf32_Ehdr
118c28d5077SSteven Rostedt # define Elf_Shdr		Elf32_Shdr
119c28d5077SSteven Rostedt # define Elf_Rel		Elf32_Rel
120c28d5077SSteven Rostedt # define Elf_Rela		Elf32_Rela
121c28d5077SSteven Rostedt # define Elf_Sym		Elf32_Sym
122c28d5077SSteven Rostedt # define ELF_R_SYM		ELF32_R_SYM
123a2d49358SJohn Reiser # define Elf_r_sym		Elf32_r_sym
124c28d5077SSteven Rostedt # define ELF_R_INFO		ELF32_R_INFO
125a2d49358SJohn Reiser # define Elf_r_info		Elf32_r_info
126c28d5077SSteven Rostedt # define ELF_ST_BIND		ELF32_ST_BIND
1279905ce8aSRabin Vincent # define ELF_ST_TYPE		ELF32_ST_TYPE
128a2d49358SJohn Reiser # define fn_ELF_R_SYM		fn_ELF32_R_SYM
129a2d49358SJohn Reiser # define fn_ELF_R_INFO		fn_ELF32_R_INFO
130c28d5077SSteven Rostedt # define uint_t			uint32_t
131c28d5077SSteven Rostedt # define _w			w
132c28d5077SSteven Rostedt # define _align			3u
133c28d5077SSteven Rostedt # define _size			4
134c28d5077SSteven Rostedt #endif
135c28d5077SSteven Rostedt 
136412910cdSWu Zhangjin /* Functions and pointers that do_file() may override for specific e_machine. */
fn_is_fake_mcount(Elf_Rel const * rp)137412910cdSWu Zhangjin static int fn_is_fake_mcount(Elf_Rel const *rp)
138412910cdSWu Zhangjin {
139412910cdSWu Zhangjin 	return 0;
140412910cdSWu Zhangjin }
141412910cdSWu Zhangjin static int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount;
142412910cdSWu Zhangjin 
fn_ELF_R_SYM(Elf_Rel const * rp)143a2d49358SJohn Reiser static uint_t fn_ELF_R_SYM(Elf_Rel const *rp)
144a2d49358SJohn Reiser {
145a2d49358SJohn Reiser 	return ELF_R_SYM(_w(rp->r_info));
146a2d49358SJohn Reiser }
147a2d49358SJohn Reiser static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM;
148a2d49358SJohn Reiser 
fn_ELF_R_INFO(Elf_Rel * const rp,unsigned sym,unsigned type)149a2d49358SJohn Reiser static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
150a2d49358SJohn Reiser {
151e63233f7SJohn Reiser 	rp->r_info = _w(ELF_R_INFO(sym, type));
152a2d49358SJohn Reiser }
153a2d49358SJohn Reiser static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
154a2d49358SJohn Reiser 
15507d8b595SMartin Schwidefsky static int mcount_adjust = 0;
15607d8b595SMartin Schwidefsky 
157412910cdSWu Zhangjin /*
158412910cdSWu Zhangjin  * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st
159412910cdSWu Zhangjin  * _mcount symbol is needed for dynamic function tracer, with it, to disable
160412910cdSWu Zhangjin  * tracing(ftrace_make_nop), the instruction in the position is replaced with
161412910cdSWu Zhangjin  * the "b label" instruction, to enable tracing(ftrace_make_call), replace the
162412910cdSWu Zhangjin  * instruction back. So, here, we set the 2nd one as fake and filter it.
163412910cdSWu Zhangjin  *
164412910cdSWu Zhangjin  * c:	3c030000	lui	v1,0x0		<-->	b	label
165412910cdSWu Zhangjin  *		c: R_MIPS_HI16	_mcount
166412910cdSWu Zhangjin  *		c: R_MIPS_NONE	*ABS*
167412910cdSWu Zhangjin  *		c: R_MIPS_NONE	*ABS*
168412910cdSWu Zhangjin  * 10:	64630000	daddiu	v1,v1,0
169412910cdSWu Zhangjin  *		10: R_MIPS_LO16	_mcount
170412910cdSWu Zhangjin  *		10: R_MIPS_NONE	*ABS*
171412910cdSWu Zhangjin  *		10: R_MIPS_NONE	*ABS*
172412910cdSWu Zhangjin  * 14:	03e0082d	move	at,ra
173412910cdSWu Zhangjin  * 18:	0060f809	jalr	v1
174412910cdSWu Zhangjin  * label:
175412910cdSWu Zhangjin  */
176412910cdSWu Zhangjin #define MIPS_FAKEMCOUNT_OFFSET	4
177412910cdSWu Zhangjin 
MIPS_is_fake_mcount(Elf_Rel const * rp)178412910cdSWu Zhangjin static int MIPS_is_fake_mcount(Elf_Rel const *rp)
179412910cdSWu Zhangjin {
18091ad11d7SAlex Smith 	static Elf_Addr old_r_offset = ~(Elf_Addr)0;
181412910cdSWu Zhangjin 	Elf_Addr current_r_offset = _w(rp->r_offset);
182412910cdSWu Zhangjin 	int is_fake;
183412910cdSWu Zhangjin 
18491ad11d7SAlex Smith 	is_fake = (old_r_offset != ~(Elf_Addr)0) &&
185412910cdSWu Zhangjin 		(current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
186412910cdSWu Zhangjin 	old_r_offset = current_r_offset;
187412910cdSWu Zhangjin 
188412910cdSWu Zhangjin 	return is_fake;
189412910cdSWu Zhangjin }
190a2d49358SJohn Reiser 
get_symindex(Elf_Sym const * sym,Elf32_Word const * symtab,Elf32_Word const * symtab_shndx)1914ef57b21SSami Tolvanen static unsigned int get_symindex(Elf_Sym const *sym, Elf32_Word const *symtab,
1924ef57b21SSami Tolvanen 				 Elf32_Word const *symtab_shndx)
1934ef57b21SSami Tolvanen {
1944ef57b21SSami Tolvanen 	unsigned long offset;
195*fb780761SPeter Zijlstra 	unsigned short shndx = w2(sym->st_shndx);
1964ef57b21SSami Tolvanen 	int index;
1974ef57b21SSami Tolvanen 
198*fb780761SPeter Zijlstra 	if (shndx > SHN_UNDEF && shndx < SHN_LORESERVE)
199*fb780761SPeter Zijlstra 		return shndx;
2004ef57b21SSami Tolvanen 
201*fb780761SPeter Zijlstra 	if (shndx == SHN_XINDEX) {
2024ef57b21SSami Tolvanen 		offset = (unsigned long)sym - (unsigned long)symtab;
2034ef57b21SSami Tolvanen 		index = offset / sizeof(*sym);
2044ef57b21SSami Tolvanen 
2054ef57b21SSami Tolvanen 		return w(symtab_shndx[index]);
2064ef57b21SSami Tolvanen 	}
2074ef57b21SSami Tolvanen 
208*fb780761SPeter Zijlstra 	return 0;
209*fb780761SPeter Zijlstra }
210*fb780761SPeter Zijlstra 
get_shnum(Elf_Ehdr const * ehdr,Elf_Shdr const * shdr0)2114ef57b21SSami Tolvanen static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
2124ef57b21SSami Tolvanen {
2134ef57b21SSami Tolvanen 	if (shdr0 && !ehdr->e_shnum)
2144ef57b21SSami Tolvanen 		return w(shdr0->sh_size);
2154ef57b21SSami Tolvanen 
2164ef57b21SSami Tolvanen 	return w2(ehdr->e_shnum);
2174ef57b21SSami Tolvanen }
2184ef57b21SSami Tolvanen 
set_shnum(Elf_Ehdr * ehdr,Elf_Shdr * shdr0,unsigned int new_shnum)2194ef57b21SSami Tolvanen static void set_shnum(Elf_Ehdr *ehdr, Elf_Shdr *shdr0, unsigned int new_shnum)
2204ef57b21SSami Tolvanen {
2214ef57b21SSami Tolvanen 	if (new_shnum >= SHN_LORESERVE) {
2224ef57b21SSami Tolvanen 		ehdr->e_shnum = 0;
2234ef57b21SSami Tolvanen 		shdr0->sh_size = w(new_shnum);
2244ef57b21SSami Tolvanen 	} else
2254ef57b21SSami Tolvanen 		ehdr->e_shnum = w2(new_shnum);
2264ef57b21SSami Tolvanen }
2274ef57b21SSami Tolvanen 
get_shstrndx(Elf_Ehdr const * ehdr,Elf_Shdr const * shdr0)2284ef57b21SSami Tolvanen static int get_shstrndx(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
2294ef57b21SSami Tolvanen {
2304ef57b21SSami Tolvanen 	if (ehdr->e_shstrndx != SHN_XINDEX)
2314ef57b21SSami Tolvanen 		return w2(ehdr->e_shstrndx);
2324ef57b21SSami Tolvanen 
2334ef57b21SSami Tolvanen 	return w(shdr0->sh_link);
2344ef57b21SSami Tolvanen }
2354ef57b21SSami Tolvanen 
find_symtab(Elf_Ehdr * const ehdr,Elf_Shdr const * shdr0,unsigned const nhdr,Elf32_Word ** symtab,Elf32_Word ** symtab_shndx)2364ef57b21SSami Tolvanen static void find_symtab(Elf_Ehdr *const ehdr, Elf_Shdr const *shdr0,
2374ef57b21SSami Tolvanen 			unsigned const nhdr, Elf32_Word **symtab,
2384ef57b21SSami Tolvanen 			Elf32_Word **symtab_shndx)
2394ef57b21SSami Tolvanen {
2404ef57b21SSami Tolvanen 	Elf_Shdr const *relhdr;
2414ef57b21SSami Tolvanen 	unsigned k;
2424ef57b21SSami Tolvanen 
2434ef57b21SSami Tolvanen 	*symtab = NULL;
2444ef57b21SSami Tolvanen 	*symtab_shndx = NULL;
2454ef57b21SSami Tolvanen 
2464ef57b21SSami Tolvanen 	for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
2474ef57b21SSami Tolvanen 		if (relhdr->sh_type == SHT_SYMTAB)
2484ef57b21SSami Tolvanen 			*symtab = (void *)ehdr + relhdr->sh_offset;
2494ef57b21SSami Tolvanen 		else if (relhdr->sh_type == SHT_SYMTAB_SHNDX)
2504ef57b21SSami Tolvanen 			*symtab_shndx = (void *)ehdr + relhdr->sh_offset;
2514ef57b21SSami Tolvanen 
2524ef57b21SSami Tolvanen 		if (*symtab && *symtab_shndx)
2534ef57b21SSami Tolvanen 			break;
2544ef57b21SSami Tolvanen 	}
2554ef57b21SSami Tolvanen }
2564ef57b21SSami Tolvanen 
257c28d5077SSteven Rostedt /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
append_func(Elf_Ehdr * const ehdr,Elf_Shdr * const shstr,uint_t const * const mloc0,uint_t const * const mlocp,Elf_Rel const * const mrel0,Elf_Rel const * const mrelp,unsigned int const rel_entsize,unsigned int const symsec_sh_link)2583f1df120SMatt Helsley static int append_func(Elf_Ehdr *const ehdr,
259c28d5077SSteven Rostedt 			Elf_Shdr *const shstr,
260c28d5077SSteven Rostedt 			uint_t const *const mloc0,
261c28d5077SSteven Rostedt 			uint_t const *const mlocp,
262c28d5077SSteven Rostedt 			Elf_Rel const *const mrel0,
263c28d5077SSteven Rostedt 			Elf_Rel const *const mrelp,
264c28d5077SSteven Rostedt 			unsigned int const rel_entsize,
265c28d5077SSteven Rostedt 			unsigned int const symsec_sh_link)
266c28d5077SSteven Rostedt {
267c28d5077SSteven Rostedt 	/* Begin constructing output file */
268c28d5077SSteven Rostedt 	Elf_Shdr mcsec;
269c28d5077SSteven Rostedt 	char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
270c28d5077SSteven Rostedt 		? ".rela__mcount_loc"
271c28d5077SSteven Rostedt 		:  ".rel__mcount_loc";
272c28d5077SSteven Rostedt 	uint_t const old_shoff = _w(ehdr->e_shoff);
273c28d5077SSteven Rostedt 	uint_t const old_shstr_sh_size   = _w(shstr->sh_size);
274c28d5077SSteven Rostedt 	uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
2754ef57b21SSami Tolvanen 	Elf_Shdr *const shdr0 = (Elf_Shdr *)(old_shoff + (void *)ehdr);
2764ef57b21SSami Tolvanen 	unsigned int const old_shnum = get_shnum(ehdr, shdr0);
2774ef57b21SSami Tolvanen 	unsigned int const new_shnum = 2 + old_shnum; /* {.rel,}__mcount_loc */
278c28d5077SSteven Rostedt 	uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
279c28d5077SSteven Rostedt 	uint_t new_e_shoff;
280c28d5077SSteven Rostedt 
281c28d5077SSteven Rostedt 	shstr->sh_size = _w(t);
282c28d5077SSteven Rostedt 	shstr->sh_offset = _w(sb.st_size);
283c28d5077SSteven Rostedt 	t += sb.st_size;
284c28d5077SSteven Rostedt 	t += (_align & -t);  /* word-byte align */
285c28d5077SSteven Rostedt 	new_e_shoff = t;
286c28d5077SSteven Rostedt 
2874ef57b21SSami Tolvanen 	set_shnum(ehdr, shdr0, new_shnum);
2884ef57b21SSami Tolvanen 
289c28d5077SSteven Rostedt 	/* body for new shstrtab */
2903f1df120SMatt Helsley 	if (ulseek(sb.st_size, SEEK_SET) < 0)
2913f1df120SMatt Helsley 		return -1;
2923f1df120SMatt Helsley 	if (uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size) < 0)
2933f1df120SMatt Helsley 		return -1;
2943f1df120SMatt Helsley 	if (uwrite(mc_name, 1 + strlen(mc_name)) < 0)
2953f1df120SMatt Helsley 		return -1;
296c28d5077SSteven Rostedt 
297c28d5077SSteven Rostedt 	/* old(modified) Elf_Shdr table, word-byte aligned */
2983f1df120SMatt Helsley 	if (ulseek(t, SEEK_SET) < 0)
2993f1df120SMatt Helsley 		return -1;
300c28d5077SSteven Rostedt 	t += sizeof(Elf_Shdr) * old_shnum;
3013f1df120SMatt Helsley 	if (uwrite(old_shoff + (void *)ehdr,
3023f1df120SMatt Helsley 	       sizeof(Elf_Shdr) * old_shnum) < 0)
3033f1df120SMatt Helsley 		return -1;
304c28d5077SSteven Rostedt 
305c28d5077SSteven Rostedt 	/* new sections __mcount_loc and .rel__mcount_loc */
306c28d5077SSteven Rostedt 	t += 2*sizeof(mcsec);
307c28d5077SSteven Rostedt 	mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
308c28d5077SSteven Rostedt 		+ old_shstr_sh_size);
309c28d5077SSteven Rostedt 	mcsec.sh_type = w(SHT_PROGBITS);
310c28d5077SSteven Rostedt 	mcsec.sh_flags = _w(SHF_ALLOC);
311c28d5077SSteven Rostedt 	mcsec.sh_addr = 0;
312c28d5077SSteven Rostedt 	mcsec.sh_offset = _w(t);
313c28d5077SSteven Rostedt 	mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
314c28d5077SSteven Rostedt 	mcsec.sh_link = 0;
315c28d5077SSteven Rostedt 	mcsec.sh_info = 0;
316c28d5077SSteven Rostedt 	mcsec.sh_addralign = _w(_size);
317c28d5077SSteven Rostedt 	mcsec.sh_entsize = _w(_size);
3183f1df120SMatt Helsley 	if (uwrite(&mcsec, sizeof(mcsec)) < 0)
3193f1df120SMatt Helsley 		return -1;
320c28d5077SSteven Rostedt 
321c28d5077SSteven Rostedt 	mcsec.sh_name = w(old_shstr_sh_size);
322c28d5077SSteven Rostedt 	mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
323c28d5077SSteven Rostedt 		? w(SHT_RELA)
324c28d5077SSteven Rostedt 		: w(SHT_REL);
325c28d5077SSteven Rostedt 	mcsec.sh_flags = 0;
326c28d5077SSteven Rostedt 	mcsec.sh_addr = 0;
327c28d5077SSteven Rostedt 	mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
328c28d5077SSteven Rostedt 	mcsec.sh_size   = _w((void *)mrelp - (void *)mrel0);
329c28d5077SSteven Rostedt 	mcsec.sh_link = w(symsec_sh_link);
330c28d5077SSteven Rostedt 	mcsec.sh_info = w(old_shnum);
331c28d5077SSteven Rostedt 	mcsec.sh_addralign = _w(_size);
332c28d5077SSteven Rostedt 	mcsec.sh_entsize = _w(rel_entsize);
333c28d5077SSteven Rostedt 
3343f1df120SMatt Helsley 	if (uwrite(&mcsec, sizeof(mcsec)) < 0)
3353f1df120SMatt Helsley 		return -1;
3363f1df120SMatt Helsley 
3373f1df120SMatt Helsley 	if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0)
3383f1df120SMatt Helsley 		return -1;
3393f1df120SMatt Helsley 	if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0)
3403f1df120SMatt Helsley 		return -1;
341c28d5077SSteven Rostedt 
342c28d5077SSteven Rostedt 	ehdr->e_shoff = _w(new_e_shoff);
3433f1df120SMatt Helsley 	if (ulseek(0, SEEK_SET) < 0)
3443f1df120SMatt Helsley 		return -1;
3453f1df120SMatt Helsley 	if (uwrite(ehdr, sizeof(*ehdr)) < 0)
3463f1df120SMatt Helsley 		return -1;
3473f1df120SMatt Helsley 	return 0;
348c28d5077SSteven Rostedt }
349c28d5077SSteven Rostedt 
get_mcountsym(Elf_Sym const * const sym0,Elf_Rel const * relp,char const * const str0)35037762cb9SSteven Rostedt static unsigned get_mcountsym(Elf_Sym const *const sym0,
35137762cb9SSteven Rostedt 			      Elf_Rel const *relp,
35237762cb9SSteven Rostedt 			      char const *const str0)
35337762cb9SSteven Rostedt {
35437762cb9SSteven Rostedt 	unsigned mcountsym = 0;
35537762cb9SSteven Rostedt 
35637762cb9SSteven Rostedt 	Elf_Sym const *const symp =
35737762cb9SSteven Rostedt 		&sym0[Elf_r_sym(relp)];
35837762cb9SSteven Rostedt 	char const *symname = &str0[w(symp->st_name)];
35937762cb9SSteven Rostedt 	char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
36048bb5dc6SSteven Rostedt 	char const *fentry = "__fentry__";
36137762cb9SSteven Rostedt 
36237762cb9SSteven Rostedt 	if (symname[0] == '.')
36337762cb9SSteven Rostedt 		++symname;  /* ppc64 hack */
36437762cb9SSteven Rostedt 	if (strcmp(mcount, symname) == 0 ||
36548bb5dc6SSteven Rostedt 	    (altmcount && strcmp(altmcount, symname) == 0) ||
36648bb5dc6SSteven Rostedt 	    (strcmp(fentry, symname) == 0))
36737762cb9SSteven Rostedt 		mcountsym = Elf_r_sym(relp);
36837762cb9SSteven Rostedt 
36937762cb9SSteven Rostedt 	return mcountsym;
37037762cb9SSteven Rostedt }
37137762cb9SSteven Rostedt 
get_sym_str_and_relp(Elf_Shdr const * const relhdr,Elf_Ehdr const * const ehdr,Elf_Sym const ** sym0,char const ** str0,Elf_Rel const ** relp)37241b402a2SSteven Rostedt static void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
37341b402a2SSteven Rostedt 				 Elf_Ehdr const *const ehdr,
37441b402a2SSteven Rostedt 				 Elf_Sym const **sym0,
37541b402a2SSteven Rostedt 				 char const **str0,
37641b402a2SSteven Rostedt 				 Elf_Rel const **relp)
37741b402a2SSteven Rostedt {
37841b402a2SSteven Rostedt 	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
37941b402a2SSteven Rostedt 		+ (void *)ehdr);
38041b402a2SSteven Rostedt 	unsigned const symsec_sh_link = w(relhdr->sh_link);
38141b402a2SSteven Rostedt 	Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
38241b402a2SSteven Rostedt 	Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
38341b402a2SSteven Rostedt 	Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
38441b402a2SSteven Rostedt 		+ (void *)ehdr);
38541b402a2SSteven Rostedt 
38641b402a2SSteven Rostedt 	*sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
38741b402a2SSteven Rostedt 				  + (void *)ehdr);
38841b402a2SSteven Rostedt 
38941b402a2SSteven Rostedt 	*str0 = (char const *)(_w(strsec->sh_offset)
39041b402a2SSteven Rostedt 			       + (void *)ehdr);
39141b402a2SSteven Rostedt 
39241b402a2SSteven Rostedt 	*relp = rel0;
39341b402a2SSteven Rostedt }
39441b402a2SSteven Rostedt 
395c28d5077SSteven Rostedt /*
396c28d5077SSteven Rostedt  * Look at the relocations in order to find the calls to mcount.
397c28d5077SSteven Rostedt  * Accumulate the section offsets that are found, and their relocation info,
398c28d5077SSteven Rostedt  * onto the end of the existing arrays.
399c28d5077SSteven Rostedt  */
sift_rel_mcount(uint_t * mlocp,unsigned const offbase,Elf_Rel ** const mrelpp,Elf_Shdr const * const relhdr,Elf_Ehdr const * const ehdr,unsigned const recsym,uint_t const recval,unsigned const reltype)400c28d5077SSteven Rostedt static uint_t *sift_rel_mcount(uint_t *mlocp,
401c28d5077SSteven Rostedt 			       unsigned const offbase,
402c28d5077SSteven Rostedt 			       Elf_Rel **const mrelpp,
403c28d5077SSteven Rostedt 			       Elf_Shdr const *const relhdr,
404c28d5077SSteven Rostedt 			       Elf_Ehdr const *const ehdr,
405c28d5077SSteven Rostedt 			       unsigned const recsym,
406c28d5077SSteven Rostedt 			       uint_t const recval,
407c28d5077SSteven Rostedt 			       unsigned const reltype)
408c28d5077SSteven Rostedt {
409c28d5077SSteven Rostedt 	uint_t *const mloc0 = mlocp;
410c28d5077SSteven Rostedt 	Elf_Rel *mrelp = *mrelpp;
41141b402a2SSteven Rostedt 	Elf_Sym const *sym0;
41241b402a2SSteven Rostedt 	char const *str0;
41341b402a2SSteven Rostedt 	Elf_Rel const *relp;
414c28d5077SSteven Rostedt 	unsigned rel_entsize = _w(relhdr->sh_entsize);
415c28d5077SSteven Rostedt 	unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
416c28d5077SSteven Rostedt 	unsigned mcountsym = 0;
417c28d5077SSteven Rostedt 	unsigned t;
418c28d5077SSteven Rostedt 
41941b402a2SSteven Rostedt 	get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
42041b402a2SSteven Rostedt 
421c28d5077SSteven Rostedt 	for (t = nrel; t; --t) {
42237762cb9SSteven Rostedt 		if (!mcountsym)
42337762cb9SSteven Rostedt 			mcountsym = get_mcountsym(sym0, relp, str0);
424c28d5077SSteven Rostedt 
42580e5302eSNaveen N. Rao 		if (mcountsym && mcountsym == Elf_r_sym(relp) &&
42680e5302eSNaveen N. Rao 				!is_fake_mcount(relp)) {
42707d8b595SMartin Schwidefsky 			uint_t const addend =
42807d8b595SMartin Schwidefsky 				_w(_w(relp->r_offset) - recval + mcount_adjust);
429c28d5077SSteven Rostedt 			mrelp->r_offset = _w(offbase
430c28d5077SSteven Rostedt 				+ ((void *)mlocp - (void *)mloc0));
431a2d49358SJohn Reiser 			Elf_r_info(mrelp, recsym, reltype);
432dd5477ffSSteven Rostedt 			if (rel_entsize == sizeof(Elf_Rela)) {
433c28d5077SSteven Rostedt 				((Elf_Rela *)mrelp)->r_addend = addend;
434c28d5077SSteven Rostedt 				*mlocp++ = 0;
435c28d5077SSteven Rostedt 			} else
436c28d5077SSteven Rostedt 				*mlocp++ = addend;
437c28d5077SSteven Rostedt 
438c28d5077SSteven Rostedt 			mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
439c28d5077SSteven Rostedt 		}
440c28d5077SSteven Rostedt 		relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
441c28d5077SSteven Rostedt 	}
442c28d5077SSteven Rostedt 	*mrelpp = mrelp;
443c28d5077SSteven Rostedt 	return mlocp;
444c28d5077SSteven Rostedt }
445c28d5077SSteven Rostedt 
446ffd618faSSteven Rostedt /*
447ffd618faSSteven Rostedt  * Read the relocation table again, but this time its called on sections
448ffd618faSSteven Rostedt  * that are not going to be traced. The mcount calls here will be converted
449ffd618faSSteven Rostedt  * into nops.
450ffd618faSSteven Rostedt  */
nop_mcount(Elf_Shdr const * const relhdr,Elf_Ehdr const * const ehdr,const char * const txtname)4513f1df120SMatt Helsley static int nop_mcount(Elf_Shdr const *const relhdr,
452dfad3d59SSteven Rostedt 		      Elf_Ehdr const *const ehdr,
453dfad3d59SSteven Rostedt 		      const char *const txtname)
454ffd618faSSteven Rostedt {
455ffd618faSSteven Rostedt 	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
456ffd618faSSteven Rostedt 		+ (void *)ehdr);
45741b402a2SSteven Rostedt 	Elf_Sym const *sym0;
45841b402a2SSteven Rostedt 	char const *str0;
45941b402a2SSteven Rostedt 	Elf_Rel const *relp;
46041b402a2SSteven Rostedt 	Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
461ffd618faSSteven Rostedt 	unsigned rel_entsize = _w(relhdr->sh_entsize);
462ffd618faSSteven Rostedt 	unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
463ffd618faSSteven Rostedt 	unsigned mcountsym = 0;
464ffd618faSSteven Rostedt 	unsigned t;
465dfad3d59SSteven Rostedt 	int once = 0;
466ffd618faSSteven Rostedt 
46741b402a2SSteven Rostedt 	get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
46841b402a2SSteven Rostedt 
469ffd618faSSteven Rostedt 	for (t = nrel; t; --t) {
470ffd618faSSteven Rostedt 		int ret = -1;
471ffd618faSSteven Rostedt 
47237762cb9SSteven Rostedt 		if (!mcountsym)
47337762cb9SSteven Rostedt 			mcountsym = get_mcountsym(sym0, relp, str0);
474ffd618faSSteven Rostedt 
475dfad3d59SSteven Rostedt 		if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
4767f8557b8SSteven Rostedt (VMware) 			if (make_nop)
477c84da8b9Slibin 				ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
478dfad3d59SSteven Rostedt 			if (warn_on_notrace_sect && !once) {
479dfad3d59SSteven Rostedt 				printf("Section %s has mcount callers being ignored\n",
480dfad3d59SSteven Rostedt 				       txtname);
481dfad3d59SSteven Rostedt 				once = 1;
482dfad3d59SSteven Rostedt 				/* just warn? */
483dfad3d59SSteven Rostedt 				if (!make_nop)
4843f1df120SMatt Helsley 					return 0;
485dfad3d59SSteven Rostedt 			}
486dfad3d59SSteven Rostedt 		}
487ffd618faSSteven Rostedt 
488ffd618faSSteven Rostedt 		/*
489ffd618faSSteven Rostedt 		 * If we successfully removed the mcount, mark the relocation
490ffd618faSSteven Rostedt 		 * as a nop (don't do anything with it).
491ffd618faSSteven Rostedt 		 */
492ffd618faSSteven Rostedt 		if (!ret) {
493ffd618faSSteven Rostedt 			Elf_Rel rel;
494ffd618faSSteven Rostedt 			rel = *(Elf_Rel *)relp;
495ffd618faSSteven Rostedt 			Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
4963f1df120SMatt Helsley 			if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0)
4973f1df120SMatt Helsley 				return -1;
4983f1df120SMatt Helsley 			if (uwrite(&rel, sizeof(rel)) < 0)
4993f1df120SMatt Helsley 				return -1;
500ffd618faSSteven Rostedt 		}
501ffd618faSSteven Rostedt 		relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
502ffd618faSSteven Rostedt 	}
5033f1df120SMatt Helsley 	return 0;
504ffd618faSSteven Rostedt }
505ffd618faSSteven Rostedt 
506c28d5077SSteven Rostedt /*
507c28d5077SSteven Rostedt  * Find a symbol in the given section, to be used as the base for relocating
508c28d5077SSteven Rostedt  * the table of offsets of calls to mcount.  A local or global symbol suffices,
509c28d5077SSteven Rostedt  * but avoid a Weak symbol because it may be overridden; the change in value
510c28d5077SSteven Rostedt  * would invalidate the relocations of the offsets of the calls to mcount.
511c28d5077SSteven Rostedt  * Often the found symbol will be the unnamed local symbol generated by
512c28d5077SSteven Rostedt  * GNU 'as' for the start of each section.  For example:
513c28d5077SSteven Rostedt  *    Num:    Value  Size Type    Bind   Vis      Ndx Name
514c28d5077SSteven Rostedt  *      2: 00000000     0 SECTION LOCAL  DEFAULT    1
515c28d5077SSteven Rostedt  */
find_secsym_ndx(unsigned const txtndx,char const * const txtname,uint_t * const recvalp,unsigned int * sym_index,Elf_Shdr const * const symhdr,Elf32_Word const * symtab,Elf32_Word const * symtab_shndx,Elf_Ehdr const * const ehdr)5163f1df120SMatt Helsley static int find_secsym_ndx(unsigned const txtndx,
517c28d5077SSteven Rostedt 				char const *const txtname,
518c28d5077SSteven Rostedt 				uint_t *const recvalp,
5193f1df120SMatt Helsley 				unsigned int *sym_index,
520c28d5077SSteven Rostedt 				Elf_Shdr const *const symhdr,
5214ef57b21SSami Tolvanen 				Elf32_Word const *symtab,
5224ef57b21SSami Tolvanen 				Elf32_Word const *symtab_shndx,
523c28d5077SSteven Rostedt 				Elf_Ehdr const *const ehdr)
524c28d5077SSteven Rostedt {
525c28d5077SSteven Rostedt 	Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
526c28d5077SSteven Rostedt 		+ (void *)ehdr);
527c28d5077SSteven Rostedt 	unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
528c28d5077SSteven Rostedt 	Elf_Sym const *symp;
529c28d5077SSteven Rostedt 	unsigned t;
530c28d5077SSteven Rostedt 
531c28d5077SSteven Rostedt 	for (symp = sym0, t = nsym; t; --t, ++symp) {
532c28d5077SSteven Rostedt 		unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
533c28d5077SSteven Rostedt 
5344ef57b21SSami Tolvanen 		if (txtndx == get_symindex(symp, symtab, symtab_shndx)
535c28d5077SSteven Rostedt 			/* avoid STB_WEAK */
536c28d5077SSteven Rostedt 		    && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
5379905ce8aSRabin Vincent 			/* function symbols on ARM have quirks, avoid them */
5389905ce8aSRabin Vincent 			if (w2(ehdr->e_machine) == EM_ARM
5399905ce8aSRabin Vincent 			    && ELF_ST_TYPE(symp->st_info) == STT_FUNC)
5409905ce8aSRabin Vincent 				continue;
5419905ce8aSRabin Vincent 
542c28d5077SSteven Rostedt 			*recvalp = _w(symp->st_value);
5433f1df120SMatt Helsley 			*sym_index = symp - sym0;
5443f1df120SMatt Helsley 			return 0;
545c28d5077SSteven Rostedt 		}
546c28d5077SSteven Rostedt 	}
547ac5db1fcSnixiaoming 	fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
548c28d5077SSteven Rostedt 		txtndx, txtname);
5493f1df120SMatt Helsley 	return -1;
550c28d5077SSteven Rostedt }
551c28d5077SSteven Rostedt 
552c28d5077SSteven Rostedt /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
__has_rel_mcount(Elf_Shdr const * const relhdr,Elf_Shdr const * const shdr0,char const * const shstrtab,char const * const fname)5533aec8638SMatt Helsley static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
554c28d5077SSteven Rostedt 				     Elf_Shdr const *const shdr0,
555c28d5077SSteven Rostedt 				     char const *const shstrtab,
556c28d5077SSteven Rostedt 				     char const *const fname)
557c28d5077SSteven Rostedt {
558c28d5077SSteven Rostedt 	/* .sh_info depends on .sh_type == SHT_REL[,A] */
559c28d5077SSteven Rostedt 	Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
560c28d5077SSteven Rostedt 	char const *const txtname = &shstrtab[w(txthdr->sh_name)];
561c28d5077SSteven Rostedt 
562dd5477ffSSteven Rostedt 	if (strcmp("__mcount_loc", txtname) == 0) {
563c28d5077SSteven Rostedt 		fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
564c28d5077SSteven Rostedt 			fname);
5653f1df120SMatt Helsley 		return already_has_rel_mcount;
566c28d5077SSteven Rostedt 	}
567dd5477ffSSteven Rostedt 	if (w(txthdr->sh_type) != SHT_PROGBITS ||
5682e885057SDavid Daney 	    !(_w(txthdr->sh_flags) & SHF_EXECINSTR))
569c28d5077SSteven Rostedt 		return NULL;
570c28d5077SSteven Rostedt 	return txtname;
571c28d5077SSteven Rostedt }
572c28d5077SSteven Rostedt 
has_rel_mcount(Elf_Shdr const * const relhdr,Elf_Shdr const * const shdr0,char const * const shstrtab,char const * const fname)573c28d5077SSteven Rostedt static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
574c28d5077SSteven Rostedt 				  Elf_Shdr const *const shdr0,
575c28d5077SSteven Rostedt 				  char const *const shstrtab,
576c28d5077SSteven Rostedt 				  char const *const fname)
577c28d5077SSteven Rostedt {
578dd5477ffSSteven Rostedt 	if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA)
579c28d5077SSteven Rostedt 		return NULL;
580c28d5077SSteven Rostedt 	return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
581c28d5077SSteven Rostedt }
582c28d5077SSteven Rostedt 
583c28d5077SSteven Rostedt 
tot_relsize(Elf_Shdr const * const shdr0,unsigned nhdr,const char * const shstrtab,const char * const fname)584c28d5077SSteven Rostedt static unsigned tot_relsize(Elf_Shdr const *const shdr0,
585c28d5077SSteven Rostedt 			    unsigned nhdr,
586c28d5077SSteven Rostedt 			    const char *const shstrtab,
587c28d5077SSteven Rostedt 			    const char *const fname)
588c28d5077SSteven Rostedt {
589c28d5077SSteven Rostedt 	unsigned totrelsz = 0;
590c28d5077SSteven Rostedt 	Elf_Shdr const *shdrp = shdr0;
591ffd618faSSteven Rostedt 	char const *txtname;
592c28d5077SSteven Rostedt 
593c28d5077SSteven Rostedt 	for (; nhdr; --nhdr, ++shdrp) {
594ffd618faSSteven Rostedt 		txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
5953f1df120SMatt Helsley 		if (txtname == already_has_rel_mcount) {
5963f1df120SMatt Helsley 			totrelsz = 0;
5973f1df120SMatt Helsley 			break;
5983f1df120SMatt Helsley 		}
599ffd618faSSteven Rostedt 		if (txtname && is_mcounted_section_name(txtname))
600c28d5077SSteven Rostedt 			totrelsz += _w(shdrp->sh_size);
601c28d5077SSteven Rostedt 	}
602c28d5077SSteven Rostedt 	return totrelsz;
603c28d5077SSteven Rostedt }
604c28d5077SSteven Rostedt 
605c28d5077SSteven Rostedt /* Overall supervision for Elf32 ET_REL file. */
do_func(Elf_Ehdr * const ehdr,char const * const fname,unsigned const reltype)6063aec8638SMatt Helsley static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
6073aec8638SMatt Helsley 		   unsigned const reltype)
608c28d5077SSteven Rostedt {
609c28d5077SSteven Rostedt 	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
610c28d5077SSteven Rostedt 		+ (void *)ehdr);
6114ef57b21SSami Tolvanen 	unsigned const nhdr = get_shnum(ehdr, shdr0);
6124ef57b21SSami Tolvanen 	Elf_Shdr *const shstr = &shdr0[get_shstrndx(ehdr, shdr0)];
613c28d5077SSteven Rostedt 	char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
614c28d5077SSteven Rostedt 		+ (void *)ehdr);
615c28d5077SSteven Rostedt 
616c28d5077SSteven Rostedt 	Elf_Shdr const *relhdr;
617c28d5077SSteven Rostedt 	unsigned k;
618c28d5077SSteven Rostedt 
6194ef57b21SSami Tolvanen 	Elf32_Word *symtab;
6204ef57b21SSami Tolvanen 	Elf32_Word *symtab_shndx;
6214ef57b21SSami Tolvanen 
622c28d5077SSteven Rostedt 	/* Upper bound on space: assume all relevant relocs are for mcount. */
6233f1df120SMatt Helsley 	unsigned       totrelsz;
624c28d5077SSteven Rostedt 
6253f1df120SMatt Helsley 	Elf_Rel *      mrel0;
6263f1df120SMatt Helsley 	Elf_Rel *      mrelp;
6273f1df120SMatt Helsley 
6283f1df120SMatt Helsley 	uint_t *      mloc0;
6293f1df120SMatt Helsley 	uint_t *      mlocp;
630c28d5077SSteven Rostedt 
631c28d5077SSteven Rostedt 	unsigned rel_entsize = 0;
632c28d5077SSteven Rostedt 	unsigned symsec_sh_link = 0;
633c28d5077SSteven Rostedt 
6343f1df120SMatt Helsley 	int result = 0;
6353f1df120SMatt Helsley 
6363f1df120SMatt Helsley 	totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
6373f1df120SMatt Helsley 	if (totrelsz == 0)
6383f1df120SMatt Helsley 		return 0;
6393f1df120SMatt Helsley 	mrel0 = umalloc(totrelsz);
6403f1df120SMatt Helsley 	mrelp = mrel0;
6413f1df120SMatt Helsley 	if (!mrel0)
6423f1df120SMatt Helsley 		return -1;
6433f1df120SMatt Helsley 
6443f1df120SMatt Helsley 	/* 2*sizeof(address) <= sizeof(Elf_Rel) */
6453f1df120SMatt Helsley 	mloc0 = umalloc(totrelsz>>1);
6463f1df120SMatt Helsley 	mlocp = mloc0;
6473f1df120SMatt Helsley 	if (!mloc0) {
6483f1df120SMatt Helsley 		free(mrel0);
6493f1df120SMatt Helsley 		return -1;
6503f1df120SMatt Helsley 	}
6513f1df120SMatt Helsley 
6524ef57b21SSami Tolvanen 	find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx);
6534ef57b21SSami Tolvanen 
654c28d5077SSteven Rostedt 	for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
655c28d5077SSteven Rostedt 		char const *const txtname = has_rel_mcount(relhdr, shdr0,
656c28d5077SSteven Rostedt 			shstrtab, fname);
6573f1df120SMatt Helsley 		if (txtname == already_has_rel_mcount) {
6583f1df120SMatt Helsley 			result = 0;
6593f1df120SMatt Helsley 			file_updated = 0;
6603f1df120SMatt Helsley 			goto out; /* Nothing to be done; don't append! */
6613f1df120SMatt Helsley 		}
662ffd618faSSteven Rostedt 		if (txtname && is_mcounted_section_name(txtname)) {
6633f1df120SMatt Helsley 			unsigned int recsym;
664c28d5077SSteven Rostedt 			uint_t recval = 0;
6653f1df120SMatt Helsley 
6663f1df120SMatt Helsley 			symsec_sh_link = w(relhdr->sh_link);
6673f1df120SMatt Helsley 			result = find_secsym_ndx(w(relhdr->sh_info), txtname,
6683f1df120SMatt Helsley 						&recval, &recsym,
6693f1df120SMatt Helsley 						&shdr0[symsec_sh_link],
6704ef57b21SSami Tolvanen 						symtab, symtab_shndx,
671c28d5077SSteven Rostedt 						ehdr);
6723f1df120SMatt Helsley 			if (result)
6733f1df120SMatt Helsley 				goto out;
674c28d5077SSteven Rostedt 
675c28d5077SSteven Rostedt 			rel_entsize = _w(relhdr->sh_entsize);
676c28d5077SSteven Rostedt 			mlocp = sift_rel_mcount(mlocp,
677c28d5077SSteven Rostedt 				(void *)mlocp - (void *)mloc0, &mrelp,
678c28d5077SSteven Rostedt 				relhdr, ehdr, recsym, recval, reltype);
679dfad3d59SSteven Rostedt 		} else if (txtname && (warn_on_notrace_sect || make_nop)) {
680ffd618faSSteven Rostedt 			/*
681ffd618faSSteven Rostedt 			 * This section is ignored by ftrace, but still
682ffd618faSSteven Rostedt 			 * has mcount calls. Convert them to nops now.
683ffd618faSSteven Rostedt 			 */
6843f1df120SMatt Helsley 			if (nop_mcount(relhdr, ehdr, txtname) < 0) {
6853f1df120SMatt Helsley 				result = -1;
6863f1df120SMatt Helsley 				goto out;
687c28d5077SSteven Rostedt 			}
688c28d5077SSteven Rostedt 		}
6893f1df120SMatt Helsley 	}
6903f1df120SMatt Helsley 	if (!result && mloc0 != mlocp)
6913f1df120SMatt Helsley 		result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
692c28d5077SSteven Rostedt 				     rel_entsize, symsec_sh_link);
6933f1df120SMatt Helsley out:
694c28d5077SSteven Rostedt 	free(mrel0);
695c28d5077SSteven Rostedt 	free(mloc0);
6963f1df120SMatt Helsley 	return result;
697c28d5077SSteven Rostedt }
698