aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-04-08 03:58:48 -0400
committerSteven Rostedt <rostedt@goodmis.org>2011-05-16 14:43:32 -0400
commitffd618fa39284f8cc343894b566dd42ec6e74e77 (patch)
tree6086848f18cb971de2e1cd760f6d8771aaff2c45 /scripts
parent8abd5724a7f1631ab2276954156c629d4d17149a (diff)
ftrace/recordmcount: Make ignored mcount calls into nops at compile time
There are sections that are ignored by ftrace for the function tracing because the text is in a section that can be removed without notice. The mcount calls in these sections are ignored and ftrace never sees them. The downside of this is that the functions in these sections still call mcount. Although the mcount function is defined in assembly simply as a return, this added overhead is unnecessary. The solution is to convert these callers into nops at compile time. A better solution is to add 'notrace' to the section markers, but as new sections come up all the time, it would be nice that they are delt with when they are created. Later patches will deal with finding these sections and doing the proper solution. Thanks to H. Peter Anvin for giving me the right nops to use for x86. Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: John Reiser <jreiser@bitwagon.com> Link: http://lkml.kernel.org/r/20110421023738.237101176@goodmis.org Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/recordmcount.c40
-rw-r--r--scripts/recordmcount.h82
2 files changed, 116 insertions, 6 deletions
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 37c59654c133..78054a41d134 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -118,6 +118,34 @@ umalloc(size_t size)
118 return addr; 118 return addr;
119} 119}
120 120
121static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 };
122static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 };
123static unsigned char *ideal_nop;
124
125static char rel_type_nop;
126
127static int (*make_nop)(void *map, size_t const offset);
128
129static int make_nop_x86(void *map, size_t const offset)
130{
131 uint32_t *ptr;
132 unsigned char *op;
133
134 /* Confirm we have 0xe8 0x0 0x0 0x0 0x0 */
135 ptr = map + offset;
136 if (*ptr != 0)
137 return -1;
138
139 op = map + offset - 1;
140 if (*op != 0xe8)
141 return -1;
142
143 /* convert to nop */
144 ulseek(fd_map, offset - 1, SEEK_SET);
145 uwrite(fd_map, ideal_nop, 5);
146 return 0;
147}
148
121/* 149/*
122 * Get the whole file as a programming convenience in order to avoid 150 * Get the whole file as a programming convenience in order to avoid
123 * malloc+lseek+read+free of many pieces. If successful, then mmap 151 * malloc+lseek+read+free of many pieces. If successful, then mmap
@@ -301,7 +329,11 @@ do_file(char const *const fname)
301 w2(ehdr->e_machine), fname); 329 w2(ehdr->e_machine), fname);
302 fail_file(); 330 fail_file();
303 break; 331 break;
304 case EM_386: reltype = R_386_32; break; 332 case EM_386:
333 reltype = R_386_32;
334 make_nop = make_nop_x86;
335 ideal_nop = ideal_nop5_x86_32;
336 break;
305 case EM_ARM: reltype = R_ARM_ABS32; 337 case EM_ARM: reltype = R_ARM_ABS32;
306 altmcount = "__gnu_mcount_nc"; 338 altmcount = "__gnu_mcount_nc";
307 break; 339 break;
@@ -312,7 +344,11 @@ do_file(char const *const fname)
312 case EM_S390: /* reltype: e_class */ gpfx = '_'; break; 344 case EM_S390: /* reltype: e_class */ gpfx = '_'; break;
313 case EM_SH: reltype = R_SH_DIR32; break; 345 case EM_SH: reltype = R_SH_DIR32; break;
314 case EM_SPARCV9: reltype = R_SPARC_64; gpfx = '_'; break; 346 case EM_SPARCV9: reltype = R_SPARC_64; gpfx = '_'; break;
315 case EM_X86_64: reltype = R_X86_64_64; break; 347 case EM_X86_64:
348 make_nop = make_nop_x86;
349 ideal_nop = ideal_nop5_x86_64;
350 reltype = R_X86_64_64;
351 break;
316 } /* end switch */ 352 } /* end switch */
317 353
318 switch (ehdr->e_ident[EI_CLASS]) { 354 switch (ehdr->e_ident[EI_CLASS]) {
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index 7f8d5c4c780f..657dbedd1c7f 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -23,6 +23,7 @@
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 sift_rel_mcount 25#undef sift_rel_mcount
26#undef nop_mcount
26#undef find_secsym_ndx 27#undef find_secsym_ndx
27#undef __has_rel_mcount 28#undef __has_rel_mcount
28#undef has_rel_mcount 29#undef has_rel_mcount
@@ -49,6 +50,7 @@
49#ifdef RECORD_MCOUNT_64 50#ifdef RECORD_MCOUNT_64
50# define append_func append64 51# define append_func append64
51# define sift_rel_mcount sift64_rel_mcount 52# define sift_rel_mcount sift64_rel_mcount
53# define nop_mcount nop_mcount_64
52# define find_secsym_ndx find64_secsym_ndx 54# define find_secsym_ndx find64_secsym_ndx
53# define __has_rel_mcount __has64_rel_mcount 55# define __has_rel_mcount __has64_rel_mcount
54# define has_rel_mcount has64_rel_mcount 56# define has_rel_mcount has64_rel_mcount
@@ -77,6 +79,7 @@
77#else 79#else
78# define append_func append32 80# define append_func append32
79# define sift_rel_mcount sift32_rel_mcount 81# define sift_rel_mcount sift32_rel_mcount
82# define nop_mcount nop_mcount_32
80# define find_secsym_ndx find32_secsym_ndx 83# define find_secsym_ndx find32_secsym_ndx
81# define __has_rel_mcount __has32_rel_mcount 84# define __has_rel_mcount __has32_rel_mcount
82# define has_rel_mcount has32_rel_mcount 85# define has_rel_mcount has32_rel_mcount
@@ -304,6 +307,70 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
304 return mlocp; 307 return mlocp;
305} 308}
306 309
310/*
311 * Read the relocation table again, but this time its called on sections
312 * that are not going to be traced. The mcount calls here will be converted
313 * into nops.
314 */
315static void nop_mcount(Elf_Shdr const *const relhdr,
316 Elf_Ehdr const *const ehdr)
317{
318 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
319 + (void *)ehdr);
320 unsigned const symsec_sh_link = w(relhdr->sh_link);
321 Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
322 Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
323 + (void *)ehdr);
324
325 Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
326 char const *const str0 = (char const *)(_w(strsec->sh_offset)
327 + (void *)ehdr);
328
329 Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
330 + (void *)ehdr);
331 unsigned rel_entsize = _w(relhdr->sh_entsize);
332 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
333 Elf_Rel const *relp = rel0;
334
335 Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
336
337 unsigned mcountsym = 0;
338 unsigned t;
339
340 for (t = nrel; t; --t) {
341 int ret = -1;
342
343 if (!mcountsym) {
344 Elf_Sym const *const symp =
345 &sym0[Elf_r_sym(relp)];
346 char const *symname = &str0[w(symp->st_name)];
347 char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
348
349 if (symname[0] == '.')
350 ++symname; /* ppc64 hack */
351 if (strcmp(mcount, symname) == 0 ||
352 (altmcount && strcmp(altmcount, symname) == 0))
353 mcountsym = Elf_r_sym(relp);
354 }
355
356 if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp))
357 ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset);
358
359 /*
360 * If we successfully removed the mcount, mark the relocation
361 * as a nop (don't do anything with it).
362 */
363 if (!ret) {
364 Elf_Rel rel;
365 rel = *(Elf_Rel *)relp;
366 Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
367 ulseek(fd_map, (void *)relp - (void *)ehdr, SEEK_SET);
368 uwrite(fd_map, &rel, sizeof(rel));
369 }
370 relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
371 }
372}
373
307 374
308/* 375/*
309 * Find a symbol in the given section, to be used as the base for relocating 376 * Find a symbol in the given section, to be used as the base for relocating
@@ -360,8 +427,7 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */
360 succeed_file(); 427 succeed_file();
361 } 428 }
362 if (w(txthdr->sh_type) != SHT_PROGBITS || 429 if (w(txthdr->sh_type) != SHT_PROGBITS ||
363 !(w(txthdr->sh_flags) & SHF_EXECINSTR) || 430 !(w(txthdr->sh_flags) & SHF_EXECINSTR))
364 !is_mcounted_section_name(txtname))
365 return NULL; 431 return NULL;
366 return txtname; 432 return txtname;
367} 433}
@@ -384,9 +450,11 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0,
384{ 450{
385 unsigned totrelsz = 0; 451 unsigned totrelsz = 0;
386 Elf_Shdr const *shdrp = shdr0; 452 Elf_Shdr const *shdrp = shdr0;
453 char const *txtname;
387 454
388 for (; nhdr; --nhdr, ++shdrp) { 455 for (; nhdr; --nhdr, ++shdrp) {
389 if (has_rel_mcount(shdrp, shdr0, shstrtab, fname)) 456 txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
457 if (txtname && is_mcounted_section_name(txtname))
390 totrelsz += _w(shdrp->sh_size); 458 totrelsz += _w(shdrp->sh_size);
391 } 459 }
392 return totrelsz; 460 return totrelsz;
@@ -422,7 +490,7 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
422 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { 490 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
423 char const *const txtname = has_rel_mcount(relhdr, shdr0, 491 char const *const txtname = has_rel_mcount(relhdr, shdr0,
424 shstrtab, fname); 492 shstrtab, fname);
425 if (txtname) { 493 if (txtname && is_mcounted_section_name(txtname)) {
426 uint_t recval = 0; 494 uint_t recval = 0;
427 unsigned const recsym = find_secsym_ndx( 495 unsigned const recsym = find_secsym_ndx(
428 w(relhdr->sh_info), txtname, &recval, 496 w(relhdr->sh_info), txtname, &recval,
@@ -433,6 +501,12 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
433 mlocp = sift_rel_mcount(mlocp, 501 mlocp = sift_rel_mcount(mlocp,
434 (void *)mlocp - (void *)mloc0, &mrelp, 502 (void *)mlocp - (void *)mloc0, &mrelp,
435 relhdr, ehdr, recsym, recval, reltype); 503 relhdr, ehdr, recsym, recval, reltype);
504 } else if (make_nop && txtname) {
505 /*
506 * This section is ignored by ftrace, but still
507 * has mcount calls. Convert them to nops now.
508 */
509 nop_mcount(relhdr, ehdr);
436 } 510 }
437 } 511 }
438 if (mloc0 != mlocp) { 512 if (mloc0 != mlocp) {