aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/recordmcount.h
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/recordmcount.h')
-rw-r--r--scripts/recordmcount.h174
1 files changed, 138 insertions, 36 deletions
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index baf187bee983..4be60364a405 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -22,11 +22,15 @@
22#undef is_fake_mcount 22#undef is_fake_mcount
23#undef fn_is_fake_mcount 23#undef fn_is_fake_mcount
24#undef MIPS_is_fake_mcount 24#undef MIPS_is_fake_mcount
25#undef mcount_adjust
25#undef sift_rel_mcount 26#undef sift_rel_mcount
27#undef nop_mcount
26#undef find_secsym_ndx 28#undef find_secsym_ndx
27#undef __has_rel_mcount 29#undef __has_rel_mcount
28#undef has_rel_mcount 30#undef has_rel_mcount
29#undef tot_relsize 31#undef tot_relsize
32#undef get_mcountsym
33#undef get_sym_str_and_relp
30#undef do_func 34#undef do_func
31#undef Elf_Addr 35#undef Elf_Addr
32#undef Elf_Ehdr 36#undef Elf_Ehdr
@@ -49,14 +53,18 @@
49#ifdef RECORD_MCOUNT_64 53#ifdef RECORD_MCOUNT_64
50# define append_func append64 54# define append_func append64
51# define sift_rel_mcount sift64_rel_mcount 55# define sift_rel_mcount sift64_rel_mcount
56# define nop_mcount nop_mcount_64
52# define find_secsym_ndx find64_secsym_ndx 57# define find_secsym_ndx find64_secsym_ndx
53# define __has_rel_mcount __has64_rel_mcount 58# define __has_rel_mcount __has64_rel_mcount
54# define has_rel_mcount has64_rel_mcount 59# define has_rel_mcount has64_rel_mcount
55# define tot_relsize tot64_relsize 60# define tot_relsize tot64_relsize
61# define get_sym_str_and_relp get_sym_str_and_relp_64
56# define do_func do64 62# define do_func do64
63# define get_mcountsym get_mcountsym_64
57# define is_fake_mcount is_fake_mcount64 64# define is_fake_mcount is_fake_mcount64
58# define fn_is_fake_mcount fn_is_fake_mcount64 65# define fn_is_fake_mcount fn_is_fake_mcount64
59# define MIPS_is_fake_mcount MIPS64_is_fake_mcount 66# define MIPS_is_fake_mcount MIPS64_is_fake_mcount
67# define mcount_adjust mcount_adjust_64
60# define Elf_Addr Elf64_Addr 68# define Elf_Addr Elf64_Addr
61# define Elf_Ehdr Elf64_Ehdr 69# define Elf_Ehdr Elf64_Ehdr
62# define Elf_Shdr Elf64_Shdr 70# define Elf_Shdr Elf64_Shdr
@@ -77,14 +85,18 @@
77#else 85#else
78# define append_func append32 86# define append_func append32
79# define sift_rel_mcount sift32_rel_mcount 87# define sift_rel_mcount sift32_rel_mcount
88# define nop_mcount nop_mcount_32
80# define find_secsym_ndx find32_secsym_ndx 89# define find_secsym_ndx find32_secsym_ndx
81# define __has_rel_mcount __has32_rel_mcount 90# define __has_rel_mcount __has32_rel_mcount
82# define has_rel_mcount has32_rel_mcount 91# define has_rel_mcount has32_rel_mcount
83# define tot_relsize tot32_relsize 92# define tot_relsize tot32_relsize
93# define get_sym_str_and_relp get_sym_str_and_relp_32
84# define do_func do32 94# define do_func do32
95# define get_mcountsym get_mcountsym_32
85# define is_fake_mcount is_fake_mcount32 96# define is_fake_mcount is_fake_mcount32
86# define fn_is_fake_mcount fn_is_fake_mcount32 97# define fn_is_fake_mcount fn_is_fake_mcount32
87# define MIPS_is_fake_mcount MIPS32_is_fake_mcount 98# define MIPS_is_fake_mcount MIPS32_is_fake_mcount
99# define mcount_adjust mcount_adjust_32
88# define Elf_Addr Elf32_Addr 100# define Elf_Addr Elf32_Addr
89# define Elf_Ehdr Elf32_Ehdr 101# define Elf_Ehdr Elf32_Ehdr
90# define Elf_Shdr Elf32_Shdr 102# define Elf_Shdr Elf32_Shdr
@@ -123,6 +135,8 @@ static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
123} 135}
124static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; 136static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
125 137
138static int mcount_adjust = 0;
139
126/* 140/*
127 * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st 141 * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st
128 * _mcount symbol is needed for dynamic function tracer, with it, to disable 142 * _mcount symbol is needed for dynamic function tracer, with it, to disable
@@ -234,6 +248,49 @@ static void append_func(Elf_Ehdr *const ehdr,
234 uwrite(fd_map, ehdr, sizeof(*ehdr)); 248 uwrite(fd_map, ehdr, sizeof(*ehdr));
235} 249}
236 250
251static unsigned get_mcountsym(Elf_Sym const *const sym0,
252 Elf_Rel const *relp,
253 char const *const str0)
254{
255 unsigned mcountsym = 0;
256
257 Elf_Sym const *const symp =
258 &sym0[Elf_r_sym(relp)];
259 char const *symname = &str0[w(symp->st_name)];
260 char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
261
262 if (symname[0] == '.')
263 ++symname; /* ppc64 hack */
264 if (strcmp(mcount, symname) == 0 ||
265 (altmcount && strcmp(altmcount, symname) == 0))
266 mcountsym = Elf_r_sym(relp);
267
268 return mcountsym;
269}
270
271static void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
272 Elf_Ehdr const *const ehdr,
273 Elf_Sym const **sym0,
274 char const **str0,
275 Elf_Rel const **relp)
276{
277 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
278 + (void *)ehdr);
279 unsigned const symsec_sh_link = w(relhdr->sh_link);
280 Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
281 Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
282 Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
283 + (void *)ehdr);
284
285 *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
286 + (void *)ehdr);
287
288 *str0 = (char const *)(_w(strsec->sh_offset)
289 + (void *)ehdr);
290
291 *relp = rel0;
292}
293
237/* 294/*
238 * Look at the relocations in order to find the calls to mcount. 295 * Look at the relocations in order to find the calls to mcount.
239 * Accumulate the section offsets that are found, and their relocation info, 296 * Accumulate the section offsets that are found, and their relocation info,
@@ -250,47 +307,27 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
250{ 307{
251 uint_t *const mloc0 = mlocp; 308 uint_t *const mloc0 = mlocp;
252 Elf_Rel *mrelp = *mrelpp; 309 Elf_Rel *mrelp = *mrelpp;
253 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) 310 Elf_Sym const *sym0;
254 + (void *)ehdr); 311 char const *str0;
255 unsigned const symsec_sh_link = w(relhdr->sh_link); 312 Elf_Rel const *relp;
256 Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
257 Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
258 + (void *)ehdr);
259
260 Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
261 char const *const str0 = (char const *)(_w(strsec->sh_offset)
262 + (void *)ehdr);
263
264 Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
265 + (void *)ehdr);
266 unsigned rel_entsize = _w(relhdr->sh_entsize); 313 unsigned rel_entsize = _w(relhdr->sh_entsize);
267 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; 314 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
268 Elf_Rel const *relp = rel0;
269
270 unsigned mcountsym = 0; 315 unsigned mcountsym = 0;
271 unsigned t; 316 unsigned t;
272 317
318 get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
319
273 for (t = nrel; t; --t) { 320 for (t = nrel; t; --t) {
274 if (!mcountsym) { 321 if (!mcountsym)
275 Elf_Sym const *const symp = 322 mcountsym = get_mcountsym(sym0, relp, str0);
276 &sym0[Elf_r_sym(relp)];
277 char const *symname = &str0[w(symp->st_name)];
278 char const *mcount = '_' == gpfx ? "_mcount" : "mcount";
279
280 if ('.' == symname[0])
281 ++symname; /* ppc64 hack */
282 if (0 == strcmp(mcount, symname) ||
283 (altmcount && 0 == strcmp(altmcount, symname)))
284 mcountsym = Elf_r_sym(relp);
285 }
286 323
287 if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { 324 if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
288 uint_t const addend = _w(_w(relp->r_offset) - recval); 325 uint_t const addend =
289 326 _w(_w(relp->r_offset) - recval + mcount_adjust);
290 mrelp->r_offset = _w(offbase 327 mrelp->r_offset = _w(offbase
291 + ((void *)mlocp - (void *)mloc0)); 328 + ((void *)mlocp - (void *)mloc0));
292 Elf_r_info(mrelp, recsym, reltype); 329 Elf_r_info(mrelp, recsym, reltype);
293 if (sizeof(Elf_Rela) == rel_entsize) { 330 if (rel_entsize == sizeof(Elf_Rela)) {
294 ((Elf_Rela *)mrelp)->r_addend = addend; 331 ((Elf_Rela *)mrelp)->r_addend = addend;
295 *mlocp++ = 0; 332 *mlocp++ = 0;
296 } else 333 } else
@@ -304,6 +341,63 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
304 return mlocp; 341 return mlocp;
305} 342}
306 343
344/*
345 * Read the relocation table again, but this time its called on sections
346 * that are not going to be traced. The mcount calls here will be converted
347 * into nops.
348 */
349static void nop_mcount(Elf_Shdr const *const relhdr,
350 Elf_Ehdr const *const ehdr,
351 const char *const txtname)
352{
353 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
354 + (void *)ehdr);
355 Elf_Sym const *sym0;
356 char const *str0;
357 Elf_Rel const *relp;
358 Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
359 unsigned rel_entsize = _w(relhdr->sh_entsize);
360 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
361 unsigned mcountsym = 0;
362 unsigned t;
363 int once = 0;
364
365 get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
366
367 for (t = nrel; t; --t) {
368 int ret = -1;
369
370 if (!mcountsym)
371 mcountsym = get_mcountsym(sym0, relp, str0);
372
373 if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
374 if (make_nop)
375 ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset);
376 if (warn_on_notrace_sect && !once) {
377 printf("Section %s has mcount callers being ignored\n",
378 txtname);
379 once = 1;
380 /* just warn? */
381 if (!make_nop)
382 return;
383 }
384 }
385
386 /*
387 * If we successfully removed the mcount, mark the relocation
388 * as a nop (don't do anything with it).
389 */
390 if (!ret) {
391 Elf_Rel rel;
392 rel = *(Elf_Rel *)relp;
393 Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
394 ulseek(fd_map, (void *)relp - (void *)ehdr, SEEK_SET);
395 uwrite(fd_map, &rel, sizeof(rel));
396 }
397 relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
398 }
399}
400
307 401
308/* 402/*
309 * Find a symbol in the given section, to be used as the base for relocating 403 * Find a symbol in the given section, to be used as the base for relocating
@@ -354,13 +448,13 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */
354 Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)]; 448 Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
355 char const *const txtname = &shstrtab[w(txthdr->sh_name)]; 449 char const *const txtname = &shstrtab[w(txthdr->sh_name)];
356 450
357 if (0 == strcmp("__mcount_loc", txtname)) { 451 if (strcmp("__mcount_loc", txtname) == 0) {
358 fprintf(stderr, "warning: __mcount_loc already exists: %s\n", 452 fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
359 fname); 453 fname);
360 succeed_file(); 454 succeed_file();
361 } 455 }
362 if (SHT_PROGBITS != w(txthdr->sh_type) || 456 if (w(txthdr->sh_type) != SHT_PROGBITS ||
363 !is_mcounted_section_name(txtname)) 457 !(w(txthdr->sh_flags) & SHF_EXECINSTR))
364 return NULL; 458 return NULL;
365 return txtname; 459 return txtname;
366} 460}
@@ -370,7 +464,7 @@ static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
370 char const *const shstrtab, 464 char const *const shstrtab,
371 char const *const fname) 465 char const *const fname)
372{ 466{
373 if (SHT_REL != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type)) 467 if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA)
374 return NULL; 468 return NULL;
375 return __has_rel_mcount(relhdr, shdr0, shstrtab, fname); 469 return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
376} 470}
@@ -383,9 +477,11 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0,
383{ 477{
384 unsigned totrelsz = 0; 478 unsigned totrelsz = 0;
385 Elf_Shdr const *shdrp = shdr0; 479 Elf_Shdr const *shdrp = shdr0;
480 char const *txtname;
386 481
387 for (; nhdr; --nhdr, ++shdrp) { 482 for (; nhdr; --nhdr, ++shdrp) {
388 if (has_rel_mcount(shdrp, shdr0, shstrtab, fname)) 483 txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
484 if (txtname && is_mcounted_section_name(txtname))
389 totrelsz += _w(shdrp->sh_size); 485 totrelsz += _w(shdrp->sh_size);
390 } 486 }
391 return totrelsz; 487 return totrelsz;
@@ -421,7 +517,7 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
421 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { 517 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
422 char const *const txtname = has_rel_mcount(relhdr, shdr0, 518 char const *const txtname = has_rel_mcount(relhdr, shdr0,
423 shstrtab, fname); 519 shstrtab, fname);
424 if (txtname) { 520 if (txtname && is_mcounted_section_name(txtname)) {
425 uint_t recval = 0; 521 uint_t recval = 0;
426 unsigned const recsym = find_secsym_ndx( 522 unsigned const recsym = find_secsym_ndx(
427 w(relhdr->sh_info), txtname, &recval, 523 w(relhdr->sh_info), txtname, &recval,
@@ -432,6 +528,12 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
432 mlocp = sift_rel_mcount(mlocp, 528 mlocp = sift_rel_mcount(mlocp,
433 (void *)mlocp - (void *)mloc0, &mrelp, 529 (void *)mlocp - (void *)mloc0, &mrelp,
434 relhdr, ehdr, recsym, recval, reltype); 530 relhdr, ehdr, recsym, recval, reltype);
531 } else if (txtname && (warn_on_notrace_sect || make_nop)) {
532 /*
533 * This section is ignored by ftrace, but still
534 * has mcount calls. Convert them to nops now.
535 */
536 nop_mcount(relhdr, ehdr, txtname);
435 } 537 }
436 } 538 }
437 if (mloc0 != mlocp) { 539 if (mloc0 != mlocp) {