aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-10-13 19:06:14 -0400
committerSteven Rostedt <rostedt@goodmis.org>2010-10-14 16:54:00 -0400
commitc28d5077f8d79bfce1e3f88db2e261cf2b6473dc (patch)
treec291f156e75beb02dfa5615a7040a549912dd8ba /scripts
parent72441cb1fd77d092f09ddfac748955703884c9a7 (diff)
ftrace: Remove duplicate code for 64 and 32 bit in recordmcount.c
The elf reader for recordmcount.c had duplicate functions for both 32 bit and 64 bit elf handling. This was due to the need of using the 32 and 64 bit elf structures. This patch consolidates the two by using macros to define the 32 and 64 bit names in a recordmcount.h file, and then by just defining a RECORD_MCOUNT_64 macro and including recordmcount.h twice we create the funtions for both the 32 bit version as well as the 64 bit version using one code source. Cc: John Reiser <jreiser@bitwagon.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/recordmcount.c548
-rw-r--r--scripts/recordmcount.h366
2 files changed, 370 insertions, 544 deletions
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 34f32be17090..7f7f7180fe24 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -212,550 +212,10 @@ is_mcounted_section_name(char const *const txtname)
212 0 == strcmp(".text.unlikely", txtname); 212 0 == strcmp(".text.unlikely", txtname);
213} 213}
214 214
215/* Append the new shstrtab, Elf32_Shdr[], __mcount_loc and its relocations. */ 215/* 32 bit and 64 bit are very similar */
216static void append32(Elf32_Ehdr *const ehdr, 216#include "recordmcount.h"
217 Elf32_Shdr *const shstr, 217#define RECORD_MCOUNT_64
218 uint32_t const *const mloc0, 218#include "recordmcount.h"
219 uint32_t const *const mlocp,
220 Elf32_Rel const *const mrel0,
221 Elf32_Rel const *const mrelp,
222 unsigned int const rel_entsize,
223 unsigned int const symsec_sh_link)
224{
225 /* Begin constructing output file */
226 Elf32_Shdr mcsec;
227 char const *mc_name = (sizeof(Elf32_Rela) == rel_entsize)
228 ? ".rela__mcount_loc"
229 : ".rel__mcount_loc";
230 unsigned const old_shnum = w2(ehdr->e_shnum);
231 uint32_t const old_shoff = w(ehdr->e_shoff);
232 uint32_t const old_shstr_sh_size = w(shstr->sh_size);
233 uint32_t const old_shstr_sh_offset = w(shstr->sh_offset);
234 uint32_t t = 1 + strlen(mc_name) + w(shstr->sh_size);
235 uint32_t new_e_shoff;
236
237 shstr->sh_size = w(t);
238 shstr->sh_offset = w(sb.st_size);
239 t += sb.st_size;
240 t += (3u & -t); /* 4-byte align */
241 new_e_shoff = t;
242
243 /* body for new shstrtab */
244 ulseek(fd_map, sb.st_size, SEEK_SET);
245 uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
246 uwrite(fd_map, mc_name, 1 + strlen(mc_name));
247
248 /* old(modified) Elf32_Shdr table, 4-byte aligned */
249 ulseek(fd_map, t, SEEK_SET);
250 t += sizeof(Elf32_Shdr) * old_shnum;
251 uwrite(fd_map, old_shoff + (void *)ehdr,
252 sizeof(Elf32_Shdr) * old_shnum);
253
254 /* new sections __mcount_loc and .rel__mcount_loc */
255 t += 2*sizeof(mcsec);
256 mcsec.sh_name = w((sizeof(Elf32_Rela) == rel_entsize) + strlen(".rel")
257 + old_shstr_sh_size);
258 mcsec.sh_type = w(SHT_PROGBITS);
259 mcsec.sh_flags = w(SHF_ALLOC);
260 mcsec.sh_addr = 0;
261 mcsec.sh_offset = w(t);
262 mcsec.sh_size = w((void *)mlocp - (void *)mloc0);
263 mcsec.sh_link = 0;
264 mcsec.sh_info = 0;
265 mcsec.sh_addralign = w(4);
266 mcsec.sh_entsize = w(4);
267 uwrite(fd_map, &mcsec, sizeof(mcsec));
268
269 mcsec.sh_name = w(old_shstr_sh_size);
270 mcsec.sh_type = (sizeof(Elf32_Rela) == rel_entsize)
271 ? w(SHT_RELA)
272 : w(SHT_REL);
273 mcsec.sh_flags = 0;
274 mcsec.sh_addr = 0;
275 mcsec.sh_offset = w((void *)mlocp - (void *)mloc0 + t);
276 mcsec.sh_size = w((void *)mrelp - (void *)mrel0);
277 mcsec.sh_link = w(symsec_sh_link);
278 mcsec.sh_info = w(old_shnum);
279 mcsec.sh_addralign = w(4);
280 mcsec.sh_entsize = w(rel_entsize);
281 uwrite(fd_map, &mcsec, sizeof(mcsec));
282
283 uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0);
284 uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0);
285
286 ehdr->e_shoff = w(new_e_shoff);
287 ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */
288 ulseek(fd_map, 0, SEEK_SET);
289 uwrite(fd_map, ehdr, sizeof(*ehdr));
290}
291
292/*
293 * append64 and append32 (and other analogous pairs) could be templated
294 * using C++, but the complexity is high. (For an example, look at p_elf.h
295 * in the source for UPX, http://upx.sourceforge.net) So: remember to make
296 * the corresponding change in the routine for the other size.
297 */
298static void append64(Elf64_Ehdr *const ehdr,
299 Elf64_Shdr *const shstr,
300 uint64_t const *const mloc0,
301 uint64_t const *const mlocp,
302 Elf64_Rel const *const mrel0,
303 Elf64_Rel const *const mrelp,
304 unsigned int const rel_entsize,
305 unsigned int const symsec_sh_link)
306{
307 /* Begin constructing output file */
308 Elf64_Shdr mcsec;
309 char const *mc_name = (sizeof(Elf64_Rela) == rel_entsize)
310 ? ".rela__mcount_loc"
311 : ".rel__mcount_loc";
312 unsigned const old_shnum = w2(ehdr->e_shnum);
313 uint64_t const old_shoff = w8(ehdr->e_shoff);
314 uint64_t const old_shstr_sh_size = w8(shstr->sh_size);
315 uint64_t const old_shstr_sh_offset = w8(shstr->sh_offset);
316 uint64_t t = 1 + strlen(mc_name) + w8(shstr->sh_size);
317 uint64_t new_e_shoff;
318
319 shstr->sh_size = w8(t);
320 shstr->sh_offset = w8(sb.st_size);
321 t += sb.st_size;
322 t += (7u & -t); /* 8-byte align */
323 new_e_shoff = t;
324
325 /* body for new shstrtab */
326 ulseek(fd_map, sb.st_size, SEEK_SET);
327 uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
328 uwrite(fd_map, mc_name, 1 + strlen(mc_name));
329
330 /* old(modified) Elf64_Shdr table, 8-byte aligned */
331 ulseek(fd_map, t, SEEK_SET);
332 t += sizeof(Elf64_Shdr) * old_shnum;
333 uwrite(fd_map, old_shoff + (void *)ehdr,
334 sizeof(Elf64_Shdr) * old_shnum);
335
336 /* new sections __mcount_loc and .rel__mcount_loc */
337 t += 2*sizeof(mcsec);
338 mcsec.sh_name = w((sizeof(Elf64_Rela) == rel_entsize) + strlen(".rel")
339 + old_shstr_sh_size);
340 mcsec.sh_type = w(SHT_PROGBITS);
341 mcsec.sh_flags = w8(SHF_ALLOC);
342 mcsec.sh_addr = 0;
343 mcsec.sh_offset = w8(t);
344 mcsec.sh_size = w8((void *)mlocp - (void *)mloc0);
345 mcsec.sh_link = 0;
346 mcsec.sh_info = 0;
347 mcsec.sh_addralign = w8(8);
348 mcsec.sh_entsize = w8(8);
349 uwrite(fd_map, &mcsec, sizeof(mcsec));
350
351 mcsec.sh_name = w(old_shstr_sh_size);
352 mcsec.sh_type = (sizeof(Elf64_Rela) == rel_entsize)
353 ? w(SHT_RELA)
354 : w(SHT_REL);
355 mcsec.sh_flags = 0;
356 mcsec.sh_addr = 0;
357 mcsec.sh_offset = w8((void *)mlocp - (void *)mloc0 + t);
358 mcsec.sh_size = w8((void *)mrelp - (void *)mrel0);
359 mcsec.sh_link = w(symsec_sh_link);
360 mcsec.sh_info = w(old_shnum);
361 mcsec.sh_addralign = w8(8);
362 mcsec.sh_entsize = w8(rel_entsize);
363 uwrite(fd_map, &mcsec, sizeof(mcsec));
364
365 uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0);
366 uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0);
367
368 ehdr->e_shoff = w8(new_e_shoff);
369 ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */
370 ulseek(fd_map, 0, SEEK_SET);
371 uwrite(fd_map, ehdr, sizeof(*ehdr));
372}
373
374/*
375 * Look at the relocations in order to find the calls to mcount.
376 * Accumulate the section offsets that are found, and their relocation info,
377 * onto the end of the existing arrays.
378 */
379static uint32_t *sift32_rel_mcount(uint32_t *mlocp,
380 unsigned const offbase,
381 Elf32_Rel **const mrelpp,
382 Elf32_Shdr const *const relhdr,
383 Elf32_Ehdr const *const ehdr,
384 unsigned const recsym,
385 uint32_t const recval,
386 unsigned const reltype)
387{
388 uint32_t *const mloc0 = mlocp;
389 Elf32_Rel *mrelp = *mrelpp;
390 Elf32_Shdr *const shdr0 = (Elf32_Shdr *)(w(ehdr->e_shoff)
391 + (void *)ehdr);
392 unsigned const symsec_sh_link = w(relhdr->sh_link);
393 Elf32_Shdr const *const symsec = &shdr0[symsec_sh_link];
394 Elf32_Sym const *const sym0 = (Elf32_Sym const *)(w(symsec->sh_offset)
395 + (void *)ehdr);
396
397 Elf32_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
398 char const *const str0 = (char const *)(w(strsec->sh_offset)
399 + (void *)ehdr);
400
401 Elf32_Rel const *const rel0 = (Elf32_Rel const *)(w(relhdr->sh_offset)
402 + (void *)ehdr);
403 unsigned rel_entsize = w(relhdr->sh_entsize);
404 unsigned const nrel = w(relhdr->sh_size) / rel_entsize;
405 Elf32_Rel const *relp = rel0;
406
407 unsigned mcountsym = 0;
408 unsigned t;
409
410 for (t = nrel; t; --t) {
411 if (!mcountsym) {
412 Elf32_Sym const *const symp =
413 &sym0[ELF32_R_SYM(w(relp->r_info))];
414
415 if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"),
416 &str0[w(symp->st_name)]))
417 mcountsym = ELF32_R_SYM(w(relp->r_info));
418 }
419 if (mcountsym == ELF32_R_SYM(w(relp->r_info))) {
420 uint32_t const addend = w(w(relp->r_offset) - recval);
421 mrelp->r_offset = w(offbase
422 + ((void *)mlocp - (void *)mloc0));
423 mrelp->r_info = w(ELF32_R_INFO(recsym, reltype));
424 if (sizeof(Elf32_Rela) == rel_entsize) {
425 ((Elf32_Rela *)mrelp)->r_addend = addend;
426 *mlocp++ = 0;
427 } else
428 *mlocp++ = addend;
429
430 mrelp = (Elf32_Rel *)(rel_entsize + (void *)mrelp);
431 }
432 relp = (Elf32_Rel const *)(rel_entsize + (void *)relp);
433 }
434 *mrelpp = mrelp;
435 return mlocp;
436}
437
438static uint64_t *sift64_rel_mcount(uint64_t *mlocp,
439 unsigned const offbase,
440 Elf64_Rel **const mrelpp,
441 Elf64_Shdr const *const relhdr,
442 Elf64_Ehdr const *const ehdr,
443 unsigned const recsym,
444 uint64_t const recval,
445 unsigned const reltype)
446{
447 uint64_t *const mloc0 = mlocp;
448 Elf64_Rel *mrelp = *mrelpp;
449 Elf64_Shdr *const shdr0 = (Elf64_Shdr *)(w8(ehdr->e_shoff)
450 + (void *)ehdr);
451 unsigned const symsec_sh_link = w(relhdr->sh_link);
452 Elf64_Shdr const *const symsec = &shdr0[symsec_sh_link];
453 Elf64_Sym const *const sym0 = (Elf64_Sym const *)(w8(symsec->sh_offset)
454 + (void *)ehdr);
455
456 Elf64_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
457 char const *const str0 = (char const *)(w8(strsec->sh_offset)
458 + (void *)ehdr);
459
460 Elf64_Rel const *const rel0 = (Elf64_Rel const *)(w8(relhdr->sh_offset)
461 + (void *)ehdr);
462 unsigned rel_entsize = w8(relhdr->sh_entsize);
463 unsigned const nrel = w8(relhdr->sh_size) / rel_entsize;
464 Elf64_Rel const *relp = rel0;
465
466 unsigned mcountsym = 0;
467 unsigned t;
468
469 for (t = nrel; 0 != t; --t) {
470 if (!mcountsym) {
471 Elf64_Sym const *const symp =
472 &sym0[ELF64_R_SYM(w8(relp->r_info))];
473 char const *symname = &str0[w(symp->st_name)];
474
475 if ('.' == symname[0])
476 ++symname; /* ppc64 hack */
477 if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"),
478 symname))
479 mcountsym = ELF64_R_SYM(w8(relp->r_info));
480 }
481
482 if (mcountsym == ELF64_R_SYM(w8(relp->r_info))) {
483 uint64_t const addend = w8(w8(relp->r_offset) - recval);
484
485 mrelp->r_offset = w8(offbase
486 + ((void *)mlocp - (void *)mloc0));
487 mrelp->r_info = w8(ELF64_R_INFO(recsym, reltype));
488 if (sizeof(Elf64_Rela) == rel_entsize) {
489 ((Elf64_Rela *)mrelp)->r_addend = addend;
490 *mlocp++ = 0;
491 } else
492 *mlocp++ = addend;
493
494 mrelp = (Elf64_Rel *)(rel_entsize + (void *)mrelp);
495 }
496 relp = (Elf64_Rel const *)(rel_entsize + (void *)relp);
497 }
498 *mrelpp = mrelp;
499
500 return mlocp;
501}
502
503/*
504 * Find a symbol in the given section, to be used as the base for relocating
505 * the table of offsets of calls to mcount. A local or global symbol suffices,
506 * but avoid a Weak symbol because it may be overridden; the change in value
507 * would invalidate the relocations of the offsets of the calls to mcount.
508 * Often the found symbol will be the unnamed local symbol generated by
509 * GNU 'as' for the start of each section. For example:
510 * Num: Value Size Type Bind Vis Ndx Name
511 * 2: 00000000 0 SECTION LOCAL DEFAULT 1
512 */
513static unsigned find32_secsym_ndx(unsigned const txtndx,
514 char const *const txtname,
515 uint32_t *const recvalp,
516 Elf32_Shdr const *const symhdr,
517 Elf32_Ehdr const *const ehdr)
518{
519 Elf32_Sym const *const sym0 = (Elf32_Sym const *)(w(symhdr->sh_offset)
520 + (void *)ehdr);
521 unsigned const nsym = w(symhdr->sh_size) / w(symhdr->sh_entsize);
522 Elf32_Sym const *symp;
523 unsigned t;
524
525 for (symp = sym0, t = nsym; t; --t, ++symp) {
526 unsigned int const st_bind = ELF32_ST_BIND(symp->st_info);
527
528 if (txtndx == w2(symp->st_shndx)
529 /* avoid STB_WEAK */
530 && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
531 *recvalp = w(symp->st_value);
532 return symp - sym0;
533 }
534 }
535 fprintf(stderr, "Cannot find symbol for section %d: %s.\n",
536 txtndx, txtname);
537 fail_file();
538}
539
540static unsigned find64_secsym_ndx(unsigned const txtndx,
541 char const *const txtname,
542 uint64_t *const recvalp,
543 Elf64_Shdr const *const symhdr,
544 Elf64_Ehdr const *const ehdr)
545{
546 Elf64_Sym const *const sym0 = (Elf64_Sym const *)(w8(symhdr->sh_offset)
547 + (void *)ehdr);
548 unsigned const nsym = w8(symhdr->sh_size) / w8(symhdr->sh_entsize);
549 Elf64_Sym const *symp;
550 unsigned t;
551
552 for (symp = sym0, t = nsym; t; --t, ++symp) {
553 unsigned int const st_bind = ELF64_ST_BIND(symp->st_info);
554
555 if (txtndx == w2(symp->st_shndx)
556 /* avoid STB_WEAK */
557 && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
558 *recvalp = w8(symp->st_value);
559 return symp - sym0;
560 }
561 }
562 fprintf(stderr, "Cannot find symbol for section %d: %s.\n",
563 txtndx, txtname);
564 fail_file();
565}
566
567/*
568 * Evade ISO C restriction: no declaration after statement in
569 * has32_rel_mcount.
570 */
571static char const *
572__has32_rel_mcount(Elf32_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */
573 Elf32_Shdr const *const shdr0,
574 char const *const shstrtab,
575 char const *const fname)
576{
577 /* .sh_info depends on .sh_type == SHT_REL[,A] */
578 Elf32_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
579 char const *const txtname = &shstrtab[w(txthdr->sh_name)];
580
581 if (0 == strcmp("__mcount_loc", txtname)) {
582 fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
583 fname);
584 succeed_file();
585 }
586 if (SHT_PROGBITS != w(txthdr->sh_type) ||
587 !is_mcounted_section_name(txtname))
588 return NULL;
589 return txtname;
590}
591
592static char const *has32_rel_mcount(Elf32_Shdr const *const relhdr,
593 Elf32_Shdr const *const shdr0,
594 char const *const shstrtab,
595 char const *const fname)
596{
597 if (SHT_REL != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type))
598 return NULL;
599 return __has32_rel_mcount(relhdr, shdr0, shstrtab, fname);
600}
601
602static char const *__has64_rel_mcount(Elf64_Shdr const *const relhdr,
603 Elf64_Shdr const *const shdr0,
604 char const *const shstrtab,
605 char const *const fname)
606{
607 /* .sh_info depends on .sh_type == SHT_REL[,A] */
608 Elf64_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
609 char const *const txtname = &shstrtab[w(txthdr->sh_name)];
610
611 if (0 == strcmp("__mcount_loc", txtname)) {
612 fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
613 fname);
614 succeed_file();
615 }
616 if (SHT_PROGBITS != w(txthdr->sh_type) ||
617 !is_mcounted_section_name(txtname))
618 return NULL;
619 return txtname;
620}
621
622static char const *has64_rel_mcount(Elf64_Shdr const *const relhdr,
623 Elf64_Shdr const *const shdr0,
624 char const *const shstrtab,
625 char const *const fname)
626{
627 if (SHT_REL != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type))
628 return NULL;
629 return __has64_rel_mcount(relhdr, shdr0, shstrtab, fname);
630}
631
632static unsigned tot32_relsize(Elf32_Shdr const *const shdr0,
633 unsigned nhdr,
634 const char *const shstrtab,
635 const char *const fname)
636{
637 unsigned totrelsz = 0;
638 Elf32_Shdr const *shdrp = shdr0;
639 for (; 0 != nhdr; --nhdr, ++shdrp) {
640 if (has32_rel_mcount(shdrp, shdr0, shstrtab, fname))
641 totrelsz += w(shdrp->sh_size);
642 }
643 return totrelsz;
644}
645
646static unsigned tot64_relsize(Elf64_Shdr const *const shdr0,
647 unsigned nhdr,
648 const char *const shstrtab,
649 const char *const fname)
650{
651 unsigned totrelsz = 0;
652 Elf64_Shdr const *shdrp = shdr0;
653
654 for (; nhdr; --nhdr, ++shdrp) {
655 if (has64_rel_mcount(shdrp, shdr0, shstrtab, fname))
656 totrelsz += w8(shdrp->sh_size);
657 }
658 return totrelsz;
659}
660
661/* Overall supervision for Elf32 ET_REL file. */
662static void
663do32(Elf32_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
664{
665 Elf32_Shdr *const shdr0 = (Elf32_Shdr *)(w(ehdr->e_shoff)
666 + (void *)ehdr);
667 unsigned const nhdr = w2(ehdr->e_shnum);
668 Elf32_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
669 char const *const shstrtab = (char const *)(w(shstr->sh_offset)
670 + (void *)ehdr);
671
672 Elf32_Shdr const *relhdr;
673 unsigned k;
674
675 /* Upper bound on space: assume all relevant relocs are for mcount. */
676 unsigned const totrelsz = tot32_relsize(shdr0, nhdr, shstrtab, fname);
677 Elf32_Rel *const mrel0 = umalloc(totrelsz);
678 Elf32_Rel * mrelp = mrel0;
679
680 /* 2*sizeof(address) <= sizeof(Elf32_Rel) */
681 uint32_t *const mloc0 = umalloc(totrelsz>>1);
682 uint32_t * mlocp = mloc0;
683
684 unsigned rel_entsize = 0;
685 unsigned symsec_sh_link = 0;
686
687 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
688 char const *const txtname = has32_rel_mcount(relhdr, shdr0,
689 shstrtab, fname);
690 if (txtname) {
691 uint32_t recval = 0;
692 unsigned const recsym = find32_secsym_ndx(
693 w(relhdr->sh_info), txtname, &recval,
694 &shdr0[symsec_sh_link = w(relhdr->sh_link)],
695 ehdr);
696
697 rel_entsize = w(relhdr->sh_entsize);
698 mlocp = sift32_rel_mcount(mlocp,
699 (void *)mlocp - (void *)mloc0, &mrelp,
700 relhdr, ehdr, recsym, recval, reltype);
701 }
702 }
703 if (mloc0 != mlocp) {
704 append32(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
705 rel_entsize, symsec_sh_link);
706 }
707 free(mrel0);
708 free(mloc0);
709}
710
711static void
712do64(Elf64_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
713{
714 Elf64_Shdr *const shdr0 = (Elf64_Shdr *)(w8(ehdr->e_shoff)
715 + (void *)ehdr);
716 unsigned const nhdr = w2(ehdr->e_shnum);
717 Elf64_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
718 char const *const shstrtab = (char const *)(w8(shstr->sh_offset)
719 + (void *)ehdr);
720
721 Elf64_Shdr const *relhdr;
722 unsigned k;
723
724 /* Upper bound on space: assume all relevant relocs are for mcount. */
725 unsigned const totrelsz = tot64_relsize(shdr0, nhdr, shstrtab, fname);
726 Elf64_Rel *const mrel0 = umalloc(totrelsz);
727 Elf64_Rel * mrelp = mrel0;
728
729 /* 2*sizeof(address) <= sizeof(Elf64_Rel) */
730 uint64_t *const mloc0 = umalloc(totrelsz>>1);
731 uint64_t * mlocp = mloc0;
732
733 unsigned rel_entsize = 0;
734 unsigned symsec_sh_link = 0;
735
736 for ((relhdr = shdr0), k = nhdr; k; --k, ++relhdr) {
737 char const *const txtname = has64_rel_mcount(relhdr, shdr0,
738 shstrtab, fname);
739 if (txtname) {
740 uint64_t recval = 0;
741 unsigned const recsym = find64_secsym_ndx(
742 w(relhdr->sh_info), txtname, &recval,
743 &shdr0[symsec_sh_link = w(relhdr->sh_link)],
744 ehdr);
745
746 rel_entsize = w8(relhdr->sh_entsize);
747 mlocp = sift64_rel_mcount(mlocp,
748 (void *)mlocp - (void *)mloc0, &mrelp,
749 relhdr, ehdr, recsym, recval, reltype);
750 }
751 }
752 if (mloc0 != mlocp) {
753 append64(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
754 rel_entsize, symsec_sh_link);
755 }
756 free(mrel0);
757 free(mloc0);
758}
759 219
760static void 220static void
761do_file(char const *const fname) 221do_file(char const *const fname)
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
new file mode 100644
index 000000000000..7f39d0943d2d
--- /dev/null
+++ b/scripts/recordmcount.h
@@ -0,0 +1,366 @@
1/*
2 * recordmcount.h
3 *
4 * This code was taken out of recordmcount.c written by
5 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
6 *
7 * The original code had the same algorithms for both 32bit
8 * and 64bit ELF files, but the code was duplicated to support
9 * the difference in structures that were used. This
10 * file creates a macro of everything that is different between
11 * the 64 and 32 bit code, such that by including this header
12 * twice we can create both sets of functions by including this
13 * header once with RECORD_MCOUNT_64 undefined, and again with
14 * it defined.
15 *
16 * This conversion to macros was done by:
17 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
18 *
19 * Licensed under the GNU General Public License, version 2 (GPLv2).
20 */
21#undef append_func
22#undef sift_rel_mcount
23#undef find_secsym_ndx
24#undef __has_rel_mcount
25#undef has_rel_mcount
26#undef tot_relsize
27#undef do_func
28#undef Elf_Ehdr
29#undef Elf_Shdr
30#undef Elf_Rel
31#undef Elf_Rela
32#undef Elf_Sym
33#undef ELF_R_SYM
34#undef ELF_R_INFO
35#undef ELF_ST_BIND
36#undef uint_t
37#undef _w
38#undef _align
39#undef _size
40
41#ifdef RECORD_MCOUNT_64
42# define append_func append64
43# define sift_rel_mcount sift64_rel_mcount
44# define find_secsym_ndx find64_secsym_ndx
45# define __has_rel_mcount __has64_rel_mcount
46# define has_rel_mcount has64_rel_mcount
47# define tot_relsize tot64_relsize
48# define do_func do64
49# define Elf_Ehdr Elf64_Ehdr
50# define Elf_Shdr Elf64_Shdr
51# define Elf_Rel Elf64_Rel
52# define Elf_Rela Elf64_Rela
53# define Elf_Sym Elf64_Sym
54# define ELF_R_SYM ELF64_R_SYM
55# define ELF_R_INFO ELF64_R_INFO
56# define ELF_ST_BIND ELF64_ST_BIND
57# define uint_t uint64_t
58# define _w w8
59# define _align 7u
60# define _size 8
61#else
62# define append_func append32
63# define sift_rel_mcount sift32_rel_mcount
64# define find_secsym_ndx find32_secsym_ndx
65# define __has_rel_mcount __has32_rel_mcount
66# define has_rel_mcount has32_rel_mcount
67# define tot_relsize tot32_relsize
68# define do_func do32
69# define Elf_Ehdr Elf32_Ehdr
70# define Elf_Shdr Elf32_Shdr
71# define Elf_Rel Elf32_Rel
72# define Elf_Rela Elf32_Rela
73# define Elf_Sym Elf32_Sym
74# define ELF_R_SYM ELF32_R_SYM
75# define ELF_R_INFO ELF32_R_INFO
76# define ELF_ST_BIND ELF32_ST_BIND
77# define uint_t uint32_t
78# define _w w
79# define _align 3u
80# define _size 4
81#endif
82
83/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
84static void append_func(Elf_Ehdr *const ehdr,
85 Elf_Shdr *const shstr,
86 uint_t const *const mloc0,
87 uint_t const *const mlocp,
88 Elf_Rel const *const mrel0,
89 Elf_Rel const *const mrelp,
90 unsigned int const rel_entsize,
91 unsigned int const symsec_sh_link)
92{
93 /* Begin constructing output file */
94 Elf_Shdr mcsec;
95 char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
96 ? ".rela__mcount_loc"
97 : ".rel__mcount_loc";
98 unsigned const old_shnum = w2(ehdr->e_shnum);
99 uint_t const old_shoff = _w(ehdr->e_shoff);
100 uint_t const old_shstr_sh_size = _w(shstr->sh_size);
101 uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
102 uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
103 uint_t new_e_shoff;
104
105 shstr->sh_size = _w(t);
106 shstr->sh_offset = _w(sb.st_size);
107 t += sb.st_size;
108 t += (_align & -t); /* word-byte align */
109 new_e_shoff = t;
110
111 /* body for new shstrtab */
112 ulseek(fd_map, sb.st_size, SEEK_SET);
113 uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
114 uwrite(fd_map, mc_name, 1 + strlen(mc_name));
115
116 /* old(modified) Elf_Shdr table, word-byte aligned */
117 ulseek(fd_map, t, SEEK_SET);
118 t += sizeof(Elf_Shdr) * old_shnum;
119 uwrite(fd_map, old_shoff + (void *)ehdr,
120 sizeof(Elf_Shdr) * old_shnum);
121
122 /* new sections __mcount_loc and .rel__mcount_loc */
123 t += 2*sizeof(mcsec);
124 mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
125 + old_shstr_sh_size);
126 mcsec.sh_type = w(SHT_PROGBITS);
127 mcsec.sh_flags = _w(SHF_ALLOC);
128 mcsec.sh_addr = 0;
129 mcsec.sh_offset = _w(t);
130 mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
131 mcsec.sh_link = 0;
132 mcsec.sh_info = 0;
133 mcsec.sh_addralign = _w(_size);
134 mcsec.sh_entsize = _w(_size);
135 uwrite(fd_map, &mcsec, sizeof(mcsec));
136
137 mcsec.sh_name = w(old_shstr_sh_size);
138 mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
139 ? w(SHT_RELA)
140 : w(SHT_REL);
141 mcsec.sh_flags = 0;
142 mcsec.sh_addr = 0;
143 mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
144 mcsec.sh_size = _w((void *)mrelp - (void *)mrel0);
145 mcsec.sh_link = w(symsec_sh_link);
146 mcsec.sh_info = w(old_shnum);
147 mcsec.sh_addralign = _w(_size);
148 mcsec.sh_entsize = _w(rel_entsize);
149 uwrite(fd_map, &mcsec, sizeof(mcsec));
150
151 uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0);
152 uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0);
153
154 ehdr->e_shoff = _w(new_e_shoff);
155 ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */
156 ulseek(fd_map, 0, SEEK_SET);
157 uwrite(fd_map, ehdr, sizeof(*ehdr));
158}
159
160
161/*
162 * Look at the relocations in order to find the calls to mcount.
163 * Accumulate the section offsets that are found, and their relocation info,
164 * onto the end of the existing arrays.
165 */
166static uint_t *sift_rel_mcount(uint_t *mlocp,
167 unsigned const offbase,
168 Elf_Rel **const mrelpp,
169 Elf_Shdr const *const relhdr,
170 Elf_Ehdr const *const ehdr,
171 unsigned const recsym,
172 uint_t const recval,
173 unsigned const reltype)
174{
175 uint_t *const mloc0 = mlocp;
176 Elf_Rel *mrelp = *mrelpp;
177 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
178 + (void *)ehdr);
179 unsigned const symsec_sh_link = w(relhdr->sh_link);
180 Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
181 Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
182 + (void *)ehdr);
183
184 Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
185 char const *const str0 = (char const *)(_w(strsec->sh_offset)
186 + (void *)ehdr);
187
188 Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
189 + (void *)ehdr);
190 unsigned rel_entsize = _w(relhdr->sh_entsize);
191 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
192 Elf_Rel const *relp = rel0;
193
194 unsigned mcountsym = 0;
195 unsigned t;
196
197 for (t = nrel; t; --t) {
198 if (!mcountsym) {
199 Elf_Sym const *const symp =
200 &sym0[ELF_R_SYM(_w(relp->r_info))];
201 char const *symname = &str0[w(symp->st_name)];
202
203 if ('.' == symname[0])
204 ++symname; /* ppc64 hack */
205 if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"),
206 symname))
207 mcountsym = ELF_R_SYM(_w(relp->r_info));
208 }
209
210 if (mcountsym == ELF_R_SYM(_w(relp->r_info))) {
211 uint_t const addend = _w(_w(relp->r_offset) - recval);
212
213 mrelp->r_offset = _w(offbase
214 + ((void *)mlocp - (void *)mloc0));
215 mrelp->r_info = _w(ELF_R_INFO(recsym, reltype));
216 if (sizeof(Elf_Rela) == rel_entsize) {
217 ((Elf_Rela *)mrelp)->r_addend = addend;
218 *mlocp++ = 0;
219 } else
220 *mlocp++ = addend;
221
222 mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
223 }
224 relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
225 }
226 *mrelpp = mrelp;
227 return mlocp;
228}
229
230
231/*
232 * Find a symbol in the given section, to be used as the base for relocating
233 * the table of offsets of calls to mcount. A local or global symbol suffices,
234 * but avoid a Weak symbol because it may be overridden; the change in value
235 * would invalidate the relocations of the offsets of the calls to mcount.
236 * Often the found symbol will be the unnamed local symbol generated by
237 * GNU 'as' for the start of each section. For example:
238 * Num: Value Size Type Bind Vis Ndx Name
239 * 2: 00000000 0 SECTION LOCAL DEFAULT 1
240 */
241static unsigned find_secsym_ndx(unsigned const txtndx,
242 char const *const txtname,
243 uint_t *const recvalp,
244 Elf_Shdr const *const symhdr,
245 Elf_Ehdr const *const ehdr)
246{
247 Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
248 + (void *)ehdr);
249 unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
250 Elf_Sym const *symp;
251 unsigned t;
252
253 for (symp = sym0, t = nsym; t; --t, ++symp) {
254 unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
255
256 if (txtndx == w2(symp->st_shndx)
257 /* avoid STB_WEAK */
258 && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
259 *recvalp = _w(symp->st_value);
260 return symp - sym0;
261 }
262 }
263 fprintf(stderr, "Cannot find symbol for section %d: %s.\n",
264 txtndx, txtname);
265 fail_file();
266}
267
268
269/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
270static char const *
271__has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */
272 Elf_Shdr const *const shdr0,
273 char const *const shstrtab,
274 char const *const fname)
275{
276 /* .sh_info depends on .sh_type == SHT_REL[,A] */
277 Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
278 char const *const txtname = &shstrtab[w(txthdr->sh_name)];
279
280 if (0 == strcmp("__mcount_loc", txtname)) {
281 fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
282 fname);
283 succeed_file();
284 }
285 if (SHT_PROGBITS != w(txthdr->sh_type) ||
286 !is_mcounted_section_name(txtname))
287 return NULL;
288 return txtname;
289}
290
291static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
292 Elf_Shdr const *const shdr0,
293 char const *const shstrtab,
294 char const *const fname)
295{
296 if (SHT_REL != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type))
297 return NULL;
298 return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
299}
300
301
302static unsigned tot_relsize(Elf_Shdr const *const shdr0,
303 unsigned nhdr,
304 const char *const shstrtab,
305 const char *const fname)
306{
307 unsigned totrelsz = 0;
308 Elf_Shdr const *shdrp = shdr0;
309
310 for (; nhdr; --nhdr, ++shdrp) {
311 if (has_rel_mcount(shdrp, shdr0, shstrtab, fname))
312 totrelsz += _w(shdrp->sh_size);
313 }
314 return totrelsz;
315}
316
317
318/* Overall supervision for Elf32 ET_REL file. */
319static void
320do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
321{
322 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
323 + (void *)ehdr);
324 unsigned const nhdr = w2(ehdr->e_shnum);
325 Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
326 char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
327 + (void *)ehdr);
328
329 Elf_Shdr const *relhdr;
330 unsigned k;
331
332 /* Upper bound on space: assume all relevant relocs are for mcount. */
333 unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
334 Elf_Rel *const mrel0 = umalloc(totrelsz);
335 Elf_Rel * mrelp = mrel0;
336
337 /* 2*sizeof(address) <= sizeof(Elf_Rel) */
338 uint_t *const mloc0 = umalloc(totrelsz>>1);
339 uint_t * mlocp = mloc0;
340
341 unsigned rel_entsize = 0;
342 unsigned symsec_sh_link = 0;
343
344 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
345 char const *const txtname = has_rel_mcount(relhdr, shdr0,
346 shstrtab, fname);
347 if (txtname) {
348 uint_t recval = 0;
349 unsigned const recsym = find_secsym_ndx(
350 w(relhdr->sh_info), txtname, &recval,
351 &shdr0[symsec_sh_link = w(relhdr->sh_link)],
352 ehdr);
353
354 rel_entsize = _w(relhdr->sh_entsize);
355 mlocp = sift_rel_mcount(mlocp,
356 (void *)mlocp - (void *)mloc0, &mrelp,
357 relhdr, ehdr, recsym, recval, reltype);
358 }
359 }
360 if (mloc0 != mlocp) {
361 append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
362 rel_entsize, symsec_sh_link);
363 }
364 free(mrel0);
365 free(mloc0);
366}