aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/recordmcount.h
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/recordmcount.h')
-rw-r--r--scripts/recordmcount.h182
1 files changed, 146 insertions, 36 deletions
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index baf187bee983..f40a6af6bf40 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
@@ -39,6 +43,7 @@
39#undef ELF_R_INFO 43#undef ELF_R_INFO
40#undef Elf_r_info 44#undef Elf_r_info
41#undef ELF_ST_BIND 45#undef ELF_ST_BIND
46#undef ELF_ST_TYPE
42#undef fn_ELF_R_SYM 47#undef fn_ELF_R_SYM
43#undef fn_ELF_R_INFO 48#undef fn_ELF_R_INFO
44#undef uint_t 49#undef uint_t
@@ -49,14 +54,18 @@
49#ifdef RECORD_MCOUNT_64 54#ifdef RECORD_MCOUNT_64
50# define append_func append64 55# define append_func append64
51# define sift_rel_mcount sift64_rel_mcount 56# define sift_rel_mcount sift64_rel_mcount
57# define nop_mcount nop_mcount_64
52# define find_secsym_ndx find64_secsym_ndx 58# define find_secsym_ndx find64_secsym_ndx
53# define __has_rel_mcount __has64_rel_mcount 59# define __has_rel_mcount __has64_rel_mcount
54# define has_rel_mcount has64_rel_mcount 60# define has_rel_mcount has64_rel_mcount
55# define tot_relsize tot64_relsize 61# define tot_relsize tot64_relsize
62# define get_sym_str_and_relp get_sym_str_and_relp_64
56# define do_func do64 63# define do_func do64
64# define get_mcountsym get_mcountsym_64
57# define is_fake_mcount is_fake_mcount64 65# define is_fake_mcount is_fake_mcount64
58# define fn_is_fake_mcount fn_is_fake_mcount64 66# define fn_is_fake_mcount fn_is_fake_mcount64
59# define MIPS_is_fake_mcount MIPS64_is_fake_mcount 67# define MIPS_is_fake_mcount MIPS64_is_fake_mcount
68# define mcount_adjust mcount_adjust_64
60# define Elf_Addr Elf64_Addr 69# define Elf_Addr Elf64_Addr
61# define Elf_Ehdr Elf64_Ehdr 70# define Elf_Ehdr Elf64_Ehdr
62# define Elf_Shdr Elf64_Shdr 71# define Elf_Shdr Elf64_Shdr
@@ -68,6 +77,7 @@
68# define ELF_R_INFO ELF64_R_INFO 77# define ELF_R_INFO ELF64_R_INFO
69# define Elf_r_info Elf64_r_info 78# define Elf_r_info Elf64_r_info
70# define ELF_ST_BIND ELF64_ST_BIND 79# define ELF_ST_BIND ELF64_ST_BIND
80# define ELF_ST_TYPE ELF64_ST_TYPE
71# define fn_ELF_R_SYM fn_ELF64_R_SYM 81# define fn_ELF_R_SYM fn_ELF64_R_SYM
72# define fn_ELF_R_INFO fn_ELF64_R_INFO 82# define fn_ELF_R_INFO fn_ELF64_R_INFO
73# define uint_t uint64_t 83# define uint_t uint64_t
@@ -77,14 +87,18 @@
77#else 87#else
78# define append_func append32 88# define append_func append32
79# define sift_rel_mcount sift32_rel_mcount 89# define sift_rel_mcount sift32_rel_mcount
90# define nop_mcount nop_mcount_32
80# define find_secsym_ndx find32_secsym_ndx 91# define find_secsym_ndx find32_secsym_ndx
81# define __has_rel_mcount __has32_rel_mcount 92# define __has_rel_mcount __has32_rel_mcount
82# define has_rel_mcount has32_rel_mcount 93# define has_rel_mcount has32_rel_mcount
83# define tot_relsize tot32_relsize 94# define tot_relsize tot32_relsize
95# define get_sym_str_and_relp get_sym_str_and_relp_32
84# define do_func do32 96# define do_func do32
97# define get_mcountsym get_mcountsym_32
85# define is_fake_mcount is_fake_mcount32 98# define is_fake_mcount is_fake_mcount32
86# define fn_is_fake_mcount fn_is_fake_mcount32 99# define fn_is_fake_mcount fn_is_fake_mcount32
87# define MIPS_is_fake_mcount MIPS32_is_fake_mcount 100# define MIPS_is_fake_mcount MIPS32_is_fake_mcount
101# define mcount_adjust mcount_adjust_32
88# define Elf_Addr Elf32_Addr 102# define Elf_Addr Elf32_Addr
89# define Elf_Ehdr Elf32_Ehdr 103# define Elf_Ehdr Elf32_Ehdr
90# define Elf_Shdr Elf32_Shdr 104# define Elf_Shdr Elf32_Shdr
@@ -96,6 +110,7 @@
96# define ELF_R_INFO ELF32_R_INFO 110# define ELF_R_INFO ELF32_R_INFO
97# define Elf_r_info Elf32_r_info 111# define Elf_r_info Elf32_r_info
98# define ELF_ST_BIND ELF32_ST_BIND 112# define ELF_ST_BIND ELF32_ST_BIND
113# define ELF_ST_TYPE ELF32_ST_TYPE
99# define fn_ELF_R_SYM fn_ELF32_R_SYM 114# define fn_ELF_R_SYM fn_ELF32_R_SYM
100# define fn_ELF_R_INFO fn_ELF32_R_INFO 115# define fn_ELF_R_INFO fn_ELF32_R_INFO
101# define uint_t uint32_t 116# define uint_t uint32_t
@@ -123,6 +138,8 @@ static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
123} 138}
124static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; 139static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
125 140
141static int mcount_adjust = 0;
142
126/* 143/*
127 * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st 144 * 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 145 * _mcount symbol is needed for dynamic function tracer, with it, to disable
@@ -234,6 +251,49 @@ static void append_func(Elf_Ehdr *const ehdr,
234 uwrite(fd_map, ehdr, sizeof(*ehdr)); 251 uwrite(fd_map, ehdr, sizeof(*ehdr));
235} 252}
236 253
254static unsigned get_mcountsym(Elf_Sym const *const sym0,
255 Elf_Rel const *relp,
256 char const *const str0)
257{
258 unsigned mcountsym = 0;
259
260 Elf_Sym const *const symp =
261 &sym0[Elf_r_sym(relp)];
262 char const *symname = &str0[w(symp->st_name)];
263 char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
264
265 if (symname[0] == '.')
266 ++symname; /* ppc64 hack */
267 if (strcmp(mcount, symname) == 0 ||
268 (altmcount && strcmp(altmcount, symname) == 0))
269 mcountsym = Elf_r_sym(relp);
270
271 return mcountsym;
272}
273
274static void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
275 Elf_Ehdr const *const ehdr,
276 Elf_Sym const **sym0,
277 char const **str0,
278 Elf_Rel const **relp)
279{
280 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
281 + (void *)ehdr);
282 unsigned const symsec_sh_link = w(relhdr->sh_link);
283 Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
284 Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
285 Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
286 + (void *)ehdr);
287
288 *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
289 + (void *)ehdr);
290
291 *str0 = (char const *)(_w(strsec->sh_offset)
292 + (void *)ehdr);
293
294 *relp = rel0;
295}
296
237/* 297/*
238 * Look at the relocations in order to find the calls to mcount. 298 * Look at the relocations in order to find the calls to mcount.
239 * Accumulate the section offsets that are found, and their relocation info, 299 * Accumulate the section offsets that are found, and their relocation info,
@@ -250,47 +310,27 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
250{ 310{
251 uint_t *const mloc0 = mlocp; 311 uint_t *const mloc0 = mlocp;
252 Elf_Rel *mrelp = *mrelpp; 312 Elf_Rel *mrelp = *mrelpp;
253 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) 313 Elf_Sym const *sym0;
254 + (void *)ehdr); 314 char const *str0;
255 unsigned const symsec_sh_link = w(relhdr->sh_link); 315 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); 316 unsigned rel_entsize = _w(relhdr->sh_entsize);
267 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; 317 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
268 Elf_Rel const *relp = rel0;
269
270 unsigned mcountsym = 0; 318 unsigned mcountsym = 0;
271 unsigned t; 319 unsigned t;
272 320
321 get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
322
273 for (t = nrel; t; --t) { 323 for (t = nrel; t; --t) {
274 if (!mcountsym) { 324 if (!mcountsym)
275 Elf_Sym const *const symp = 325 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 326
287 if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { 327 if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
288 uint_t const addend = _w(_w(relp->r_offset) - recval); 328 uint_t const addend =
289 329 _w(_w(relp->r_offset) - recval + mcount_adjust);
290 mrelp->r_offset = _w(offbase 330 mrelp->r_offset = _w(offbase
291 + ((void *)mlocp - (void *)mloc0)); 331 + ((void *)mlocp - (void *)mloc0));
292 Elf_r_info(mrelp, recsym, reltype); 332 Elf_r_info(mrelp, recsym, reltype);
293 if (sizeof(Elf_Rela) == rel_entsize) { 333 if (rel_entsize == sizeof(Elf_Rela)) {
294 ((Elf_Rela *)mrelp)->r_addend = addend; 334 ((Elf_Rela *)mrelp)->r_addend = addend;
295 *mlocp++ = 0; 335 *mlocp++ = 0;
296 } else 336 } else
@@ -304,6 +344,63 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
304 return mlocp; 344 return mlocp;
305} 345}
306 346
347/*
348 * Read the relocation table again, but this time its called on sections
349 * that are not going to be traced. The mcount calls here will be converted
350 * into nops.
351 */
352static void nop_mcount(Elf_Shdr const *const relhdr,
353 Elf_Ehdr const *const ehdr,
354 const char *const txtname)
355{
356 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
357 + (void *)ehdr);
358 Elf_Sym const *sym0;
359 char const *str0;
360 Elf_Rel const *relp;
361 Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
362 unsigned rel_entsize = _w(relhdr->sh_entsize);
363 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
364 unsigned mcountsym = 0;
365 unsigned t;
366 int once = 0;
367
368 get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
369
370 for (t = nrel; t; --t) {
371 int ret = -1;
372
373 if (!mcountsym)
374 mcountsym = get_mcountsym(sym0, relp, str0);
375
376 if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
377 if (make_nop)
378 ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset);
379 if (warn_on_notrace_sect && !once) {
380 printf("Section %s has mcount callers being ignored\n",
381 txtname);
382 once = 1;
383 /* just warn? */
384 if (!make_nop)
385 return;
386 }
387 }
388
389 /*
390 * If we successfully removed the mcount, mark the relocation
391 * as a nop (don't do anything with it).
392 */
393 if (!ret) {
394 Elf_Rel rel;
395 rel = *(Elf_Rel *)relp;
396 Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
397 ulseek(fd_map, (void *)relp - (void *)ehdr, SEEK_SET);
398 uwrite(fd_map, &rel, sizeof(rel));
399 }
400 relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
401 }
402}
403
307 404
308/* 405/*
309 * Find a symbol in the given section, to be used as the base for relocating 406 * Find a symbol in the given section, to be used as the base for relocating
@@ -333,6 +430,11 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
333 if (txtndx == w2(symp->st_shndx) 430 if (txtndx == w2(symp->st_shndx)
334 /* avoid STB_WEAK */ 431 /* avoid STB_WEAK */
335 && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) { 432 && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
433 /* function symbols on ARM have quirks, avoid them */
434 if (w2(ehdr->e_machine) == EM_ARM
435 && ELF_ST_TYPE(symp->st_info) == STT_FUNC)
436 continue;
437
336 *recvalp = _w(symp->st_value); 438 *recvalp = _w(symp->st_value);
337 return symp - sym0; 439 return symp - sym0;
338 } 440 }
@@ -354,13 +456,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)]; 456 Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
355 char const *const txtname = &shstrtab[w(txthdr->sh_name)]; 457 char const *const txtname = &shstrtab[w(txthdr->sh_name)];
356 458
357 if (0 == strcmp("__mcount_loc", txtname)) { 459 if (strcmp("__mcount_loc", txtname) == 0) {
358 fprintf(stderr, "warning: __mcount_loc already exists: %s\n", 460 fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
359 fname); 461 fname);
360 succeed_file(); 462 succeed_file();
361 } 463 }
362 if (SHT_PROGBITS != w(txthdr->sh_type) || 464 if (w(txthdr->sh_type) != SHT_PROGBITS ||
363 !is_mcounted_section_name(txtname)) 465 !(w(txthdr->sh_flags) & SHF_EXECINSTR))
364 return NULL; 466 return NULL;
365 return txtname; 467 return txtname;
366} 468}
@@ -370,7 +472,7 @@ static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
370 char const *const shstrtab, 472 char const *const shstrtab,
371 char const *const fname) 473 char const *const fname)
372{ 474{
373 if (SHT_REL != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type)) 475 if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA)
374 return NULL; 476 return NULL;
375 return __has_rel_mcount(relhdr, shdr0, shstrtab, fname); 477 return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
376} 478}
@@ -383,9 +485,11 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0,
383{ 485{
384 unsigned totrelsz = 0; 486 unsigned totrelsz = 0;
385 Elf_Shdr const *shdrp = shdr0; 487 Elf_Shdr const *shdrp = shdr0;
488 char const *txtname;
386 489
387 for (; nhdr; --nhdr, ++shdrp) { 490 for (; nhdr; --nhdr, ++shdrp) {
388 if (has_rel_mcount(shdrp, shdr0, shstrtab, fname)) 491 txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
492 if (txtname && is_mcounted_section_name(txtname))
389 totrelsz += _w(shdrp->sh_size); 493 totrelsz += _w(shdrp->sh_size);
390 } 494 }
391 return totrelsz; 495 return totrelsz;
@@ -421,7 +525,7 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
421 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { 525 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
422 char const *const txtname = has_rel_mcount(relhdr, shdr0, 526 char const *const txtname = has_rel_mcount(relhdr, shdr0,
423 shstrtab, fname); 527 shstrtab, fname);
424 if (txtname) { 528 if (txtname && is_mcounted_section_name(txtname)) {
425 uint_t recval = 0; 529 uint_t recval = 0;
426 unsigned const recsym = find_secsym_ndx( 530 unsigned const recsym = find_secsym_ndx(
427 w(relhdr->sh_info), txtname, &recval, 531 w(relhdr->sh_info), txtname, &recval,
@@ -432,6 +536,12 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
432 mlocp = sift_rel_mcount(mlocp, 536 mlocp = sift_rel_mcount(mlocp,
433 (void *)mlocp - (void *)mloc0, &mrelp, 537 (void *)mlocp - (void *)mloc0, &mrelp,
434 relhdr, ehdr, recsym, recval, reltype); 538 relhdr, ehdr, recsym, recval, reltype);
539 } else if (txtname && (warn_on_notrace_sect || make_nop)) {
540 /*
541 * This section is ignored by ftrace, but still
542 * has mcount calls. Convert them to nops now.
543 */
544 nop_mcount(relhdr, ehdr, txtname);
435 } 545 }
436 } 546 }
437 if (mloc0 != mlocp) { 547 if (mloc0 != mlocp) {