diff options
Diffstat (limited to 'scripts/recordmcount.h')
-rw-r--r-- | scripts/recordmcount.h | 174 |
1 files changed, 138 insertions, 36 deletions
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index baf187bee98..4be60364a40 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 | } |
124 | static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; | 136 | static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; |
125 | 137 | ||
138 | static 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 | ||
251 | static 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 | |||
271 | static 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 | */ | ||
349 | static 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) { |