Blame view

scripts/recordmcount.h 17.1 KB
4317cf95c   Thomas Gleixner   treewide: Replace...
1
  /* SPDX-License-Identifier: GPL-2.0-only */
c28d5077f   Steven Rostedt   ftrace: Remove du...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * recordmcount.h
   *
   * This code was taken out of recordmcount.c written by
   * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
   *
   * The original code had the same algorithms for both 32bit
   * and 64bit ELF files, but the code was duplicated to support
   * the difference in structures that were used. This
   * file creates a macro of everything that is different between
   * the 64 and 32 bit code, such that by including this header
   * twice we can create both sets of functions by including this
   * header once with RECORD_MCOUNT_64 undefined, and again with
   * it defined.
   *
   * This conversion to macros was done by:
   * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
c28d5077f   Steven Rostedt   ftrace: Remove du...
19
20
   */
  #undef append_func
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
21
22
23
  #undef is_fake_mcount
  #undef fn_is_fake_mcount
  #undef MIPS_is_fake_mcount
07d8b595f   Martin Schwidefsky   ftrace/recordmcou...
24
  #undef mcount_adjust
c28d5077f   Steven Rostedt   ftrace: Remove du...
25
  #undef sift_rel_mcount
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
26
  #undef nop_mcount
c28d5077f   Steven Rostedt   ftrace: Remove du...
27
28
29
30
  #undef find_secsym_ndx
  #undef __has_rel_mcount
  #undef has_rel_mcount
  #undef tot_relsize
37762cb99   Steven Rostedt   ftrace/recordmcou...
31
  #undef get_mcountsym
41b402a20   Steven Rostedt   ftrace/recordmcou...
32
  #undef get_sym_str_and_relp
c28d5077f   Steven Rostedt   ftrace: Remove du...
33
  #undef do_func
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
34
  #undef Elf_Addr
c28d5077f   Steven Rostedt   ftrace: Remove du...
35
36
37
38
39
40
  #undef Elf_Ehdr
  #undef Elf_Shdr
  #undef Elf_Rel
  #undef Elf_Rela
  #undef Elf_Sym
  #undef ELF_R_SYM
a2d49358b   John Reiser   ftrace/MIPS: Add ...
41
  #undef Elf_r_sym
c28d5077f   Steven Rostedt   ftrace: Remove du...
42
  #undef ELF_R_INFO
a2d49358b   John Reiser   ftrace/MIPS: Add ...
43
  #undef Elf_r_info
c28d5077f   Steven Rostedt   ftrace: Remove du...
44
  #undef ELF_ST_BIND
9905ce8ad   Rabin Vincent   ftrace/recordmcou...
45
  #undef ELF_ST_TYPE
a2d49358b   John Reiser   ftrace/MIPS: Add ...
46
47
  #undef fn_ELF_R_SYM
  #undef fn_ELF_R_INFO
c28d5077f   Steven Rostedt   ftrace: Remove du...
48
49
50
51
52
53
54
55
  #undef uint_t
  #undef _w
  #undef _align
  #undef _size
  
  #ifdef RECORD_MCOUNT_64
  # define append_func		append64
  # define sift_rel_mcount	sift64_rel_mcount
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
56
  # define nop_mcount		nop_mcount_64
c28d5077f   Steven Rostedt   ftrace: Remove du...
57
58
59
60
  # define find_secsym_ndx	find64_secsym_ndx
  # define __has_rel_mcount	__has64_rel_mcount
  # define has_rel_mcount		has64_rel_mcount
  # define tot_relsize		tot64_relsize
41b402a20   Steven Rostedt   ftrace/recordmcou...
61
  # define get_sym_str_and_relp	get_sym_str_and_relp_64
c28d5077f   Steven Rostedt   ftrace: Remove du...
62
  # define do_func		do64
37762cb99   Steven Rostedt   ftrace/recordmcou...
63
  # define get_mcountsym		get_mcountsym_64
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
64
65
66
  # 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
07d8b595f   Martin Schwidefsky   ftrace/recordmcou...
67
  # define mcount_adjust		mcount_adjust_64
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
68
  # define Elf_Addr		Elf64_Addr
c28d5077f   Steven Rostedt   ftrace: Remove du...
69
70
71
72
73
74
  # 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
a2d49358b   John Reiser   ftrace/MIPS: Add ...
75
  # define Elf_r_sym		Elf64_r_sym
c28d5077f   Steven Rostedt   ftrace: Remove du...
76
  # define ELF_R_INFO		ELF64_R_INFO
a2d49358b   John Reiser   ftrace/MIPS: Add ...
77
  # define Elf_r_info		Elf64_r_info
c28d5077f   Steven Rostedt   ftrace: Remove du...
78
  # define ELF_ST_BIND		ELF64_ST_BIND
9905ce8ad   Rabin Vincent   ftrace/recordmcou...
79
  # define ELF_ST_TYPE		ELF64_ST_TYPE
a2d49358b   John Reiser   ftrace/MIPS: Add ...
80
81
  # define fn_ELF_R_SYM		fn_ELF64_R_SYM
  # define fn_ELF_R_INFO		fn_ELF64_R_INFO
c28d5077f   Steven Rostedt   ftrace: Remove du...
82
83
84
85
86
87
88
  # define uint_t			uint64_t
  # define _w			w8
  # define _align			7u
  # define _size			8
  #else
  # define append_func		append32
  # define sift_rel_mcount	sift32_rel_mcount
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
89
  # define nop_mcount		nop_mcount_32
c28d5077f   Steven Rostedt   ftrace: Remove du...
90
91
92
93
  # define find_secsym_ndx	find32_secsym_ndx
  # define __has_rel_mcount	__has32_rel_mcount
  # define has_rel_mcount		has32_rel_mcount
  # define tot_relsize		tot32_relsize
41b402a20   Steven Rostedt   ftrace/recordmcou...
94
  # define get_sym_str_and_relp	get_sym_str_and_relp_32
c28d5077f   Steven Rostedt   ftrace: Remove du...
95
  # define do_func		do32
37762cb99   Steven Rostedt   ftrace/recordmcou...
96
  # define get_mcountsym		get_mcountsym_32
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
97
98
99
  # 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
07d8b595f   Martin Schwidefsky   ftrace/recordmcou...
100
  # define mcount_adjust		mcount_adjust_32
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
101
  # define Elf_Addr		Elf32_Addr
c28d5077f   Steven Rostedt   ftrace: Remove du...
102
103
104
105
106
107
  # 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
a2d49358b   John Reiser   ftrace/MIPS: Add ...
108
  # define Elf_r_sym		Elf32_r_sym
c28d5077f   Steven Rostedt   ftrace: Remove du...
109
  # define ELF_R_INFO		ELF32_R_INFO
a2d49358b   John Reiser   ftrace/MIPS: Add ...
110
  # define Elf_r_info		Elf32_r_info
c28d5077f   Steven Rostedt   ftrace: Remove du...
111
  # define ELF_ST_BIND		ELF32_ST_BIND
9905ce8ad   Rabin Vincent   ftrace/recordmcou...
112
  # define ELF_ST_TYPE		ELF32_ST_TYPE
a2d49358b   John Reiser   ftrace/MIPS: Add ...
113
114
  # define fn_ELF_R_SYM		fn_ELF32_R_SYM
  # define fn_ELF_R_INFO		fn_ELF32_R_INFO
c28d5077f   Steven Rostedt   ftrace: Remove du...
115
116
117
118
119
  # define uint_t			uint32_t
  # define _w			w
  # define _align			3u
  # define _size			4
  #endif
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
120
121
122
123
124
125
  /* 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;
a2d49358b   John Reiser   ftrace/MIPS: Add ...
126
127
128
129
130
131
132
133
  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)
  {
e63233f75   John Reiser   ftrace: Have reco...
134
  	rp->r_info = _w(ELF_R_INFO(sym, type));
a2d49358b   John Reiser   ftrace/MIPS: Add ...
135
136
  }
  static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
07d8b595f   Martin Schwidefsky   ftrace/recordmcou...
137
  static int mcount_adjust = 0;
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  /*
   * 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)
  {
91ad11d7c   Alex Smith   recordmcount/MIPS...
161
  	static Elf_Addr old_r_offset = ~(Elf_Addr)0;
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
162
163
  	Elf_Addr current_r_offset = _w(rp->r_offset);
  	int is_fake;
91ad11d7c   Alex Smith   recordmcount/MIPS...
164
  	is_fake = (old_r_offset != ~(Elf_Addr)0) &&
412910cd0   Wu Zhangjin   ftrace/MIPS: Add ...
165
166
167
168
169
  		(current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
  	old_r_offset = current_r_offset;
  
  	return is_fake;
  }
a2d49358b   John Reiser   ftrace/MIPS: Add ...
170

c28d5077f   Steven Rostedt   ftrace: Remove du...
171
  /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
3f1df1201   Matt Helsley   recordmcount: Rew...
172
  static int append_func(Elf_Ehdr *const ehdr,
c28d5077f   Steven Rostedt   ftrace: Remove du...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  			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)
  {
  	/* Begin constructing output file */
  	Elf_Shdr mcsec;
  	char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
  		? ".rela__mcount_loc"
  		:  ".rel__mcount_loc";
  	unsigned const old_shnum = w2(ehdr->e_shnum);
  	uint_t const old_shoff = _w(ehdr->e_shoff);
  	uint_t const old_shstr_sh_size   = _w(shstr->sh_size);
  	uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
  	uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
  	uint_t new_e_shoff;
  
  	shstr->sh_size = _w(t);
  	shstr->sh_offset = _w(sb.st_size);
  	t += sb.st_size;
  	t += (_align & -t);  /* word-byte align */
  	new_e_shoff = t;
  
  	/* body for new shstrtab */
3f1df1201   Matt Helsley   recordmcount: Rew...
200
201
202
203
204
205
  	if (ulseek(sb.st_size, SEEK_SET) < 0)
  		return -1;
  	if (uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size) < 0)
  		return -1;
  	if (uwrite(mc_name, 1 + strlen(mc_name)) < 0)
  		return -1;
c28d5077f   Steven Rostedt   ftrace: Remove du...
206
207
  
  	/* old(modified) Elf_Shdr table, word-byte aligned */
3f1df1201   Matt Helsley   recordmcount: Rew...
208
209
  	if (ulseek(t, SEEK_SET) < 0)
  		return -1;
c28d5077f   Steven Rostedt   ftrace: Remove du...
210
  	t += sizeof(Elf_Shdr) * old_shnum;
3f1df1201   Matt Helsley   recordmcount: Rew...
211
212
213
  	if (uwrite(old_shoff + (void *)ehdr,
  	       sizeof(Elf_Shdr) * old_shnum) < 0)
  		return -1;
c28d5077f   Steven Rostedt   ftrace: Remove du...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  
  	/* new sections __mcount_loc and .rel__mcount_loc */
  	t += 2*sizeof(mcsec);
  	mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
  		+ old_shstr_sh_size);
  	mcsec.sh_type = w(SHT_PROGBITS);
  	mcsec.sh_flags = _w(SHF_ALLOC);
  	mcsec.sh_addr = 0;
  	mcsec.sh_offset = _w(t);
  	mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
  	mcsec.sh_link = 0;
  	mcsec.sh_info = 0;
  	mcsec.sh_addralign = _w(_size);
  	mcsec.sh_entsize = _w(_size);
3f1df1201   Matt Helsley   recordmcount: Rew...
228
229
  	if (uwrite(&mcsec, sizeof(mcsec)) < 0)
  		return -1;
c28d5077f   Steven Rostedt   ftrace: Remove du...
230
231
232
233
234
235
236
237
238
239
240
241
242
  
  	mcsec.sh_name = w(old_shstr_sh_size);
  	mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
  		? w(SHT_RELA)
  		: w(SHT_REL);
  	mcsec.sh_flags = 0;
  	mcsec.sh_addr = 0;
  	mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
  	mcsec.sh_size   = _w((void *)mrelp - (void *)mrel0);
  	mcsec.sh_link = w(symsec_sh_link);
  	mcsec.sh_info = w(old_shnum);
  	mcsec.sh_addralign = _w(_size);
  	mcsec.sh_entsize = _w(rel_entsize);
c28d5077f   Steven Rostedt   ftrace: Remove du...
243

3f1df1201   Matt Helsley   recordmcount: Rew...
244
245
246
247
248
249
250
  	if (uwrite(&mcsec, sizeof(mcsec)) < 0)
  		return -1;
  
  	if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0)
  		return -1;
  	if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0)
  		return -1;
c28d5077f   Steven Rostedt   ftrace: Remove du...
251
252
253
  
  	ehdr->e_shoff = _w(new_e_shoff);
  	ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum));  /* {.rel,}__mcount_loc */
3f1df1201   Matt Helsley   recordmcount: Rew...
254
255
256
257
258
  	if (ulseek(0, SEEK_SET) < 0)
  		return -1;
  	if (uwrite(ehdr, sizeof(*ehdr)) < 0)
  		return -1;
  	return 0;
c28d5077f   Steven Rostedt   ftrace: Remove du...
259
  }
37762cb99   Steven Rostedt   ftrace/recordmcou...
260
261
262
263
264
265
266
267
268
269
  static unsigned get_mcountsym(Elf_Sym const *const sym0,
  			      Elf_Rel const *relp,
  			      char const *const str0)
  {
  	unsigned mcountsym = 0;
  
  	Elf_Sym const *const symp =
  		&sym0[Elf_r_sym(relp)];
  	char const *symname = &str0[w(symp->st_name)];
  	char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
48bb5dc6c   Steven Rostedt   ftrace: Make reco...
270
  	char const *fentry = "__fentry__";
37762cb99   Steven Rostedt   ftrace/recordmcou...
271
272
273
274
  
  	if (symname[0] == '.')
  		++symname;  /* ppc64 hack */
  	if (strcmp(mcount, symname) == 0 ||
48bb5dc6c   Steven Rostedt   ftrace: Make reco...
275
276
  	    (altmcount && strcmp(altmcount, symname) == 0) ||
  	    (strcmp(fentry, symname) == 0))
37762cb99   Steven Rostedt   ftrace/recordmcou...
277
278
279
280
  		mcountsym = Elf_r_sym(relp);
  
  	return mcountsym;
  }
41b402a20   Steven Rostedt   ftrace/recordmcou...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  static void 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)
  {
  	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
  		+ (void *)ehdr);
  	unsigned const symsec_sh_link = w(relhdr->sh_link);
  	Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
  	Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
  	Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
  		+ (void *)ehdr);
  
  	*sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
  				  + (void *)ehdr);
  
  	*str0 = (char const *)(_w(strsec->sh_offset)
  			       + (void *)ehdr);
  
  	*relp = rel0;
  }
c28d5077f   Steven Rostedt   ftrace: Remove du...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  /*
   * Look at the relocations in order to find the calls to mcount.
   * Accumulate the section offsets that are found, and their relocation info,
   * onto the end of the existing arrays.
   */
  static uint_t *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)
  {
  	uint_t *const mloc0 = mlocp;
  	Elf_Rel *mrelp = *mrelpp;
41b402a20   Steven Rostedt   ftrace/recordmcou...
319
320
321
  	Elf_Sym const *sym0;
  	char const *str0;
  	Elf_Rel const *relp;
c28d5077f   Steven Rostedt   ftrace: Remove du...
322
323
  	unsigned rel_entsize = _w(relhdr->sh_entsize);
  	unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
c28d5077f   Steven Rostedt   ftrace: Remove du...
324
325
  	unsigned mcountsym = 0;
  	unsigned t;
41b402a20   Steven Rostedt   ftrace/recordmcou...
326
  	get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
c28d5077f   Steven Rostedt   ftrace: Remove du...
327
  	for (t = nrel; t; --t) {
37762cb99   Steven Rostedt   ftrace/recordmcou...
328
329
  		if (!mcountsym)
  			mcountsym = get_mcountsym(sym0, relp, str0);
c28d5077f   Steven Rostedt   ftrace: Remove du...
330

80e5302e4   Naveen N. Rao   recordmcount: Fix...
331
332
  		if (mcountsym && mcountsym == Elf_r_sym(relp) &&
  				!is_fake_mcount(relp)) {
07d8b595f   Martin Schwidefsky   ftrace/recordmcou...
333
334
  			uint_t const addend =
  				_w(_w(relp->r_offset) - recval + mcount_adjust);
c28d5077f   Steven Rostedt   ftrace: Remove du...
335
336
  			mrelp->r_offset = _w(offbase
  				+ ((void *)mlocp - (void *)mloc0));
a2d49358b   John Reiser   ftrace/MIPS: Add ...
337
  			Elf_r_info(mrelp, recsym, reltype);
dd5477ff3   Steven Rostedt   ftrace/trivial: C...
338
  			if (rel_entsize == sizeof(Elf_Rela)) {
c28d5077f   Steven Rostedt   ftrace: Remove du...
339
340
341
342
343
344
345
346
347
348
349
350
  				((Elf_Rela *)mrelp)->r_addend = addend;
  				*mlocp++ = 0;
  			} else
  				*mlocp++ = addend;
  
  			mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
  		}
  		relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
  	}
  	*mrelpp = mrelp;
  	return mlocp;
  }
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
351
352
353
354
355
  /*
   * Read the relocation table again, but this time its called on sections
   * that are not going to be traced. The mcount calls here will be converted
   * into nops.
   */
3f1df1201   Matt Helsley   recordmcount: Rew...
356
357
358
  static int nop_mcount(Elf_Shdr const *const relhdr,
  		      Elf_Ehdr const *const ehdr,
  		      const char *const txtname)
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
359
360
361
  {
  	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
  		+ (void *)ehdr);
41b402a20   Steven Rostedt   ftrace/recordmcou...
362
363
364
365
  	Elf_Sym const *sym0;
  	char const *str0;
  	Elf_Rel const *relp;
  	Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
366
367
  	unsigned rel_entsize = _w(relhdr->sh_entsize);
  	unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
368
369
  	unsigned mcountsym = 0;
  	unsigned t;
dfad3d598   Steven Rostedt   ftrace/recordmcou...
370
  	int once = 0;
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
371

41b402a20   Steven Rostedt   ftrace/recordmcou...
372
  	get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
373
374
  	for (t = nrel; t; --t) {
  		int ret = -1;
37762cb99   Steven Rostedt   ftrace/recordmcou...
375
376
  		if (!mcountsym)
  			mcountsym = get_mcountsym(sym0, relp, str0);
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
377

dfad3d598   Steven Rostedt   ftrace/recordmcou...
378
  		if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
7f8557b88   Steven Rostedt (VMware)   recordmcount: Fix...
379
  			if (make_nop)
c84da8b9a   libin   recordmcount: Fix...
380
  				ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
dfad3d598   Steven Rostedt   ftrace/recordmcou...
381
382
383
384
385
386
387
  			if (warn_on_notrace_sect && !once) {
  				printf("Section %s has mcount callers being ignored
  ",
  				       txtname);
  				once = 1;
  				/* just warn? */
  				if (!make_nop)
3f1df1201   Matt Helsley   recordmcount: Rew...
388
  					return 0;
dfad3d598   Steven Rostedt   ftrace/recordmcou...
389
390
  			}
  		}
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
391
392
393
394
395
396
397
398
399
  
  		/*
  		 * If we successfully removed the mcount, mark the relocation
  		 * as a nop (don't do anything with it).
  		 */
  		if (!ret) {
  			Elf_Rel rel;
  			rel = *(Elf_Rel *)relp;
  			Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
3f1df1201   Matt Helsley   recordmcount: Rew...
400
401
402
403
  			if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0)
  				return -1;
  			if (uwrite(&rel, sizeof(rel)) < 0)
  				return -1;
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
404
405
406
  		}
  		relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
  	}
3f1df1201   Matt Helsley   recordmcount: Rew...
407
  	return 0;
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
408
  }
c28d5077f   Steven Rostedt   ftrace: Remove du...
409
410
411
412
413
414
415
416
417
418
  /*
   * Find a symbol in the given section, to be used as the base for relocating
   * the table of offsets of calls to mcount.  A local or global symbol suffices,
   * but avoid a Weak symbol because it may be overridden; the change in value
   * would invalidate the relocations of the offsets of the calls to mcount.
   * Often the found symbol will be the unnamed local symbol generated by
   * GNU 'as' for the start of each section.  For example:
   *    Num:    Value  Size Type    Bind   Vis      Ndx Name
   *      2: 00000000     0 SECTION LOCAL  DEFAULT    1
   */
3f1df1201   Matt Helsley   recordmcount: Rew...
419
  static int find_secsym_ndx(unsigned const txtndx,
c28d5077f   Steven Rostedt   ftrace: Remove du...
420
421
  				char const *const txtname,
  				uint_t *const recvalp,
3f1df1201   Matt Helsley   recordmcount: Rew...
422
  				unsigned int *sym_index,
c28d5077f   Steven Rostedt   ftrace: Remove du...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  				Elf_Shdr const *const symhdr,
  				Elf_Ehdr const *const ehdr)
  {
  	Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
  		+ (void *)ehdr);
  	unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
  	Elf_Sym const *symp;
  	unsigned t;
  
  	for (symp = sym0, t = nsym; t; --t, ++symp) {
  		unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
  
  		if (txtndx == w2(symp->st_shndx)
  			/* avoid STB_WEAK */
  		    && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
9905ce8ad   Rabin Vincent   ftrace/recordmcou...
438
439
440
441
  			/* function symbols on ARM have quirks, avoid them */
  			if (w2(ehdr->e_machine) == EM_ARM
  			    && ELF_ST_TYPE(symp->st_info) == STT_FUNC)
  				continue;
c28d5077f   Steven Rostedt   ftrace: Remove du...
442
  			*recvalp = _w(symp->st_value);
3f1df1201   Matt Helsley   recordmcount: Rew...
443
444
  			*sym_index = symp - sym0;
  			return 0;
c28d5077f   Steven Rostedt   ftrace: Remove du...
445
446
  		}
  	}
ac5db1fc8   nixiaoming   scripts: Fixed pr...
447
448
  	fprintf(stderr, "Cannot find symbol for section %u: %s.
  ",
c28d5077f   Steven Rostedt   ftrace: Remove du...
449
  		txtndx, txtname);
3f1df1201   Matt Helsley   recordmcount: Rew...
450
  	return -1;
c28d5077f   Steven Rostedt   ftrace: Remove du...
451
  }
c28d5077f   Steven Rostedt   ftrace: Remove du...
452
  /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
3aec86382   Matt Helsley   recordmcount: Ker...
453
454
455
456
  static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
  				     Elf_Shdr const *const shdr0,
  				     char const *const shstrtab,
  				     char const *const fname)
c28d5077f   Steven Rostedt   ftrace: Remove du...
457
458
459
460
  {
  	/* .sh_info depends on .sh_type == SHT_REL[,A] */
  	Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
  	char const *const txtname = &shstrtab[w(txthdr->sh_name)];
dd5477ff3   Steven Rostedt   ftrace/trivial: C...
461
  	if (strcmp("__mcount_loc", txtname) == 0) {
c28d5077f   Steven Rostedt   ftrace: Remove du...
462
463
464
  		fprintf(stderr, "warning: __mcount_loc already exists: %s
  ",
  			fname);
3f1df1201   Matt Helsley   recordmcount: Rew...
465
  		return already_has_rel_mcount;
c28d5077f   Steven Rostedt   ftrace: Remove du...
466
  	}
dd5477ff3   Steven Rostedt   ftrace/trivial: C...
467
  	if (w(txthdr->sh_type) != SHT_PROGBITS ||
2e885057b   David Daney   recordmcount: Fix...
468
  	    !(_w(txthdr->sh_flags) & SHF_EXECINSTR))
c28d5077f   Steven Rostedt   ftrace: Remove du...
469
470
471
472
473
474
475
476
477
  		return NULL;
  	return txtname;
  }
  
  static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
  				  Elf_Shdr const *const shdr0,
  				  char const *const shstrtab,
  				  char const *const fname)
  {
dd5477ff3   Steven Rostedt   ftrace/trivial: C...
478
  	if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA)
c28d5077f   Steven Rostedt   ftrace: Remove du...
479
480
481
482
483
484
485
486
487
488
489
490
  		return NULL;
  	return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
  }
  
  
  static unsigned tot_relsize(Elf_Shdr const *const shdr0,
  			    unsigned nhdr,
  			    const char *const shstrtab,
  			    const char *const fname)
  {
  	unsigned totrelsz = 0;
  	Elf_Shdr const *shdrp = shdr0;
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
491
  	char const *txtname;
c28d5077f   Steven Rostedt   ftrace: Remove du...
492
493
  
  	for (; nhdr; --nhdr, ++shdrp) {
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
494
  		txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
3f1df1201   Matt Helsley   recordmcount: Rew...
495
496
497
498
  		if (txtname == already_has_rel_mcount) {
  			totrelsz = 0;
  			break;
  		}
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
499
  		if (txtname && is_mcounted_section_name(txtname))
c28d5077f   Steven Rostedt   ftrace: Remove du...
500
501
502
503
504
505
506
  			totrelsz += _w(shdrp->sh_size);
  	}
  	return totrelsz;
  }
  
  
  /* Overall supervision for Elf32 ET_REL file. */
3aec86382   Matt Helsley   recordmcount: Ker...
507
508
  static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
  		   unsigned const reltype)
c28d5077f   Steven Rostedt   ftrace: Remove du...
509
510
511
512
513
514
515
516
517
518
519
520
  {
  	Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
  		+ (void *)ehdr);
  	unsigned const nhdr = w2(ehdr->e_shnum);
  	Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
  	char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
  		+ (void *)ehdr);
  
  	Elf_Shdr const *relhdr;
  	unsigned k;
  
  	/* Upper bound on space: assume all relevant relocs are for mcount. */
3f1df1201   Matt Helsley   recordmcount: Rew...
521
  	unsigned       totrelsz;
c28d5077f   Steven Rostedt   ftrace: Remove du...
522

3f1df1201   Matt Helsley   recordmcount: Rew...
523
524
525
526
527
  	Elf_Rel *      mrel0;
  	Elf_Rel *      mrelp;
  
  	uint_t *      mloc0;
  	uint_t *      mlocp;
c28d5077f   Steven Rostedt   ftrace: Remove du...
528
529
530
  
  	unsigned rel_entsize = 0;
  	unsigned symsec_sh_link = 0;
3f1df1201   Matt Helsley   recordmcount: Rew...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  	int result = 0;
  
  	totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
  	if (totrelsz == 0)
  		return 0;
  	mrel0 = umalloc(totrelsz);
  	mrelp = mrel0;
  	if (!mrel0)
  		return -1;
  
  	/* 2*sizeof(address) <= sizeof(Elf_Rel) */
  	mloc0 = umalloc(totrelsz>>1);
  	mlocp = mloc0;
  	if (!mloc0) {
  		free(mrel0);
  		return -1;
  	}
c28d5077f   Steven Rostedt   ftrace: Remove du...
548
549
550
  	for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
  		char const *const txtname = has_rel_mcount(relhdr, shdr0,
  			shstrtab, fname);
3f1df1201   Matt Helsley   recordmcount: Rew...
551
552
553
554
555
  		if (txtname == already_has_rel_mcount) {
  			result = 0;
  			file_updated = 0;
  			goto out; /* Nothing to be done; don't append! */
  		}
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
556
  		if (txtname && is_mcounted_section_name(txtname)) {
3f1df1201   Matt Helsley   recordmcount: Rew...
557
  			unsigned int recsym;
c28d5077f   Steven Rostedt   ftrace: Remove du...
558
  			uint_t recval = 0;
3f1df1201   Matt Helsley   recordmcount: Rew...
559
560
561
562
563
564
565
566
  
  			symsec_sh_link = w(relhdr->sh_link);
  			result = find_secsym_ndx(w(relhdr->sh_info), txtname,
  						&recval, &recsym,
  						&shdr0[symsec_sh_link],
  						ehdr);
  			if (result)
  				goto out;
c28d5077f   Steven Rostedt   ftrace: Remove du...
567
568
569
570
571
  
  			rel_entsize = _w(relhdr->sh_entsize);
  			mlocp = sift_rel_mcount(mlocp,
  				(void *)mlocp - (void *)mloc0, &mrelp,
  				relhdr, ehdr, recsym, recval, reltype);
dfad3d598   Steven Rostedt   ftrace/recordmcou...
572
  		} else if (txtname && (warn_on_notrace_sect || make_nop)) {
ffd618fa3   Steven Rostedt   ftrace/recordmcou...
573
574
575
576
  			/*
  			 * This section is ignored by ftrace, but still
  			 * has mcount calls. Convert them to nops now.
  			 */
3f1df1201   Matt Helsley   recordmcount: Rew...
577
578
579
580
  			if (nop_mcount(relhdr, ehdr, txtname) < 0) {
  				result = -1;
  				goto out;
  			}
c28d5077f   Steven Rostedt   ftrace: Remove du...
581
582
  		}
  	}
3f1df1201   Matt Helsley   recordmcount: Rew...
583
584
585
586
  	if (!result && mloc0 != mlocp)
  		result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
  				     rel_entsize, symsec_sh_link);
  out:
c28d5077f   Steven Rostedt   ftrace: Remove du...
587
588
  	free(mrel0);
  	free(mloc0);
3f1df1201   Matt Helsley   recordmcount: Rew...
589
  	return result;
c28d5077f   Steven Rostedt   ftrace: Remove du...
590
  }