aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}