diff options
Diffstat (limited to 'scripts/recordmcount.h')
| -rw-r--r-- | scripts/recordmcount.h | 86 |
1 files changed, 81 insertions, 5 deletions
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 7f39d0943d2d..58e933a20544 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h | |||
| @@ -19,20 +19,28 @@ | |||
| 19 | * Licensed under the GNU General Public License, version 2 (GPLv2). | 19 | * Licensed under the GNU General Public License, version 2 (GPLv2). |
| 20 | */ | 20 | */ |
| 21 | #undef append_func | 21 | #undef append_func |
| 22 | #undef is_fake_mcount | ||
| 23 | #undef fn_is_fake_mcount | ||
| 24 | #undef MIPS_is_fake_mcount | ||
| 22 | #undef sift_rel_mcount | 25 | #undef sift_rel_mcount |
| 23 | #undef find_secsym_ndx | 26 | #undef find_secsym_ndx |
| 24 | #undef __has_rel_mcount | 27 | #undef __has_rel_mcount |
| 25 | #undef has_rel_mcount | 28 | #undef has_rel_mcount |
| 26 | #undef tot_relsize | 29 | #undef tot_relsize |
| 27 | #undef do_func | 30 | #undef do_func |
| 31 | #undef Elf_Addr | ||
| 28 | #undef Elf_Ehdr | 32 | #undef Elf_Ehdr |
| 29 | #undef Elf_Shdr | 33 | #undef Elf_Shdr |
| 30 | #undef Elf_Rel | 34 | #undef Elf_Rel |
| 31 | #undef Elf_Rela | 35 | #undef Elf_Rela |
| 32 | #undef Elf_Sym | 36 | #undef Elf_Sym |
| 33 | #undef ELF_R_SYM | 37 | #undef ELF_R_SYM |
| 38 | #undef Elf_r_sym | ||
| 34 | #undef ELF_R_INFO | 39 | #undef ELF_R_INFO |
| 40 | #undef Elf_r_info | ||
| 35 | #undef ELF_ST_BIND | 41 | #undef ELF_ST_BIND |
| 42 | #undef fn_ELF_R_SYM | ||
| 43 | #undef fn_ELF_R_INFO | ||
| 36 | #undef uint_t | 44 | #undef uint_t |
| 37 | #undef _w | 45 | #undef _w |
| 38 | #undef _align | 46 | #undef _align |
| @@ -46,14 +54,22 @@ | |||
| 46 | # define has_rel_mcount has64_rel_mcount | 54 | # define has_rel_mcount has64_rel_mcount |
| 47 | # define tot_relsize tot64_relsize | 55 | # define tot_relsize tot64_relsize |
| 48 | # define do_func do64 | 56 | # define do_func do64 |
| 57 | # define is_fake_mcount is_fake_mcount64 | ||
| 58 | # define fn_is_fake_mcount fn_is_fake_mcount64 | ||
| 59 | # define MIPS_is_fake_mcount MIPS64_is_fake_mcount | ||
| 60 | # define Elf_Addr Elf64_Addr | ||
| 49 | # define Elf_Ehdr Elf64_Ehdr | 61 | # define Elf_Ehdr Elf64_Ehdr |
| 50 | # define Elf_Shdr Elf64_Shdr | 62 | # define Elf_Shdr Elf64_Shdr |
| 51 | # define Elf_Rel Elf64_Rel | 63 | # define Elf_Rel Elf64_Rel |
| 52 | # define Elf_Rela Elf64_Rela | 64 | # define Elf_Rela Elf64_Rela |
| 53 | # define Elf_Sym Elf64_Sym | 65 | # define Elf_Sym Elf64_Sym |
| 54 | # define ELF_R_SYM ELF64_R_SYM | 66 | # define ELF_R_SYM ELF64_R_SYM |
| 67 | # define Elf_r_sym Elf64_r_sym | ||
| 55 | # define ELF_R_INFO ELF64_R_INFO | 68 | # define ELF_R_INFO ELF64_R_INFO |
| 69 | # define Elf_r_info Elf64_r_info | ||
| 56 | # define ELF_ST_BIND ELF64_ST_BIND | 70 | # define ELF_ST_BIND ELF64_ST_BIND |
| 71 | # define fn_ELF_R_SYM fn_ELF64_R_SYM | ||
| 72 | # define fn_ELF_R_INFO fn_ELF64_R_INFO | ||
| 57 | # define uint_t uint64_t | 73 | # define uint_t uint64_t |
| 58 | # define _w w8 | 74 | # define _w w8 |
| 59 | # define _align 7u | 75 | # define _align 7u |
| @@ -66,20 +82,81 @@ | |||
| 66 | # define has_rel_mcount has32_rel_mcount | 82 | # define has_rel_mcount has32_rel_mcount |
| 67 | # define tot_relsize tot32_relsize | 83 | # define tot_relsize tot32_relsize |
| 68 | # define do_func do32 | 84 | # define do_func do32 |
| 85 | # define is_fake_mcount is_fake_mcount32 | ||
| 86 | # define fn_is_fake_mcount fn_is_fake_mcount32 | ||
| 87 | # define MIPS_is_fake_mcount MIPS32_is_fake_mcount | ||
| 88 | # define Elf_Addr Elf32_Addr | ||
| 69 | # define Elf_Ehdr Elf32_Ehdr | 89 | # define Elf_Ehdr Elf32_Ehdr |
| 70 | # define Elf_Shdr Elf32_Shdr | 90 | # define Elf_Shdr Elf32_Shdr |
| 71 | # define Elf_Rel Elf32_Rel | 91 | # define Elf_Rel Elf32_Rel |
| 72 | # define Elf_Rela Elf32_Rela | 92 | # define Elf_Rela Elf32_Rela |
| 73 | # define Elf_Sym Elf32_Sym | 93 | # define Elf_Sym Elf32_Sym |
| 74 | # define ELF_R_SYM ELF32_R_SYM | 94 | # define ELF_R_SYM ELF32_R_SYM |
| 95 | # define Elf_r_sym Elf32_r_sym | ||
| 75 | # define ELF_R_INFO ELF32_R_INFO | 96 | # define ELF_R_INFO ELF32_R_INFO |
| 97 | # define Elf_r_info Elf32_r_info | ||
| 76 | # define ELF_ST_BIND ELF32_ST_BIND | 98 | # define ELF_ST_BIND ELF32_ST_BIND |
| 99 | # define fn_ELF_R_SYM fn_ELF32_R_SYM | ||
| 100 | # define fn_ELF_R_INFO fn_ELF32_R_INFO | ||
| 77 | # define uint_t uint32_t | 101 | # define uint_t uint32_t |
| 78 | # define _w w | 102 | # define _w w |
| 79 | # define _align 3u | 103 | # define _align 3u |
| 80 | # define _size 4 | 104 | # define _size 4 |
| 81 | #endif | 105 | #endif |
| 82 | 106 | ||
| 107 | /* Functions and pointers that do_file() may override for specific e_machine. */ | ||
| 108 | static int fn_is_fake_mcount(Elf_Rel const *rp) | ||
| 109 | { | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | static int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount; | ||
| 113 | |||
| 114 | static uint_t fn_ELF_R_SYM(Elf_Rel const *rp) | ||
| 115 | { | ||
| 116 | return ELF_R_SYM(_w(rp->r_info)); | ||
| 117 | } | ||
| 118 | static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM; | ||
| 119 | |||
| 120 | static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type) | ||
| 121 | { | ||
| 122 | rp->r_info = ELF_R_INFO(sym, type); | ||
| 123 | } | ||
| 124 | static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; | ||
| 125 | |||
| 126 | /* | ||
| 127 | * 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 | ||
| 129 | * tracing(ftrace_make_nop), the instruction in the position is replaced with | ||
| 130 | * the "b label" instruction, to enable tracing(ftrace_make_call), replace the | ||
| 131 | * instruction back. So, here, we set the 2nd one as fake and filter it. | ||
| 132 | * | ||
| 133 | * c: 3c030000 lui v1,0x0 <--> b label | ||
| 134 | * c: R_MIPS_HI16 _mcount | ||
| 135 | * c: R_MIPS_NONE *ABS* | ||
| 136 | * c: R_MIPS_NONE *ABS* | ||
| 137 | * 10: 64630000 daddiu v1,v1,0 | ||
| 138 | * 10: R_MIPS_LO16 _mcount | ||
| 139 | * 10: R_MIPS_NONE *ABS* | ||
| 140 | * 10: R_MIPS_NONE *ABS* | ||
| 141 | * 14: 03e0082d move at,ra | ||
| 142 | * 18: 0060f809 jalr v1 | ||
| 143 | * label: | ||
| 144 | */ | ||
| 145 | #define MIPS_FAKEMCOUNT_OFFSET 4 | ||
| 146 | |||
| 147 | static int MIPS_is_fake_mcount(Elf_Rel const *rp) | ||
| 148 | { | ||
| 149 | static Elf_Addr old_r_offset; | ||
| 150 | Elf_Addr current_r_offset = _w(rp->r_offset); | ||
| 151 | int is_fake; | ||
| 152 | |||
| 153 | is_fake = old_r_offset && | ||
| 154 | (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET); | ||
| 155 | old_r_offset = current_r_offset; | ||
| 156 | |||
| 157 | return is_fake; | ||
| 158 | } | ||
| 159 | |||
| 83 | /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ | 160 | /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ |
| 84 | static void append_func(Elf_Ehdr *const ehdr, | 161 | static void append_func(Elf_Ehdr *const ehdr, |
| 85 | Elf_Shdr *const shstr, | 162 | Elf_Shdr *const shstr, |
| @@ -157,7 +234,6 @@ static void append_func(Elf_Ehdr *const ehdr, | |||
| 157 | uwrite(fd_map, ehdr, sizeof(*ehdr)); | 234 | uwrite(fd_map, ehdr, sizeof(*ehdr)); |
| 158 | } | 235 | } |
| 159 | 236 | ||
| 160 | |||
| 161 | /* | 237 | /* |
| 162 | * Look at the relocations in order to find the calls to mcount. | 238 | * Look at the relocations in order to find the calls to mcount. |
| 163 | * Accumulate the section offsets that are found, and their relocation info, | 239 | * Accumulate the section offsets that are found, and their relocation info, |
| @@ -197,22 +273,22 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, | |||
| 197 | for (t = nrel; t; --t) { | 273 | for (t = nrel; t; --t) { |
| 198 | if (!mcountsym) { | 274 | if (!mcountsym) { |
| 199 | Elf_Sym const *const symp = | 275 | Elf_Sym const *const symp = |
| 200 | &sym0[ELF_R_SYM(_w(relp->r_info))]; | 276 | &sym0[Elf_r_sym(relp)]; |
| 201 | char const *symname = &str0[w(symp->st_name)]; | 277 | char const *symname = &str0[w(symp->st_name)]; |
| 202 | 278 | ||
| 203 | if ('.' == symname[0]) | 279 | if ('.' == symname[0]) |
| 204 | ++symname; /* ppc64 hack */ | 280 | ++symname; /* ppc64 hack */ |
| 205 | if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"), | 281 | if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"), |
| 206 | symname)) | 282 | symname)) |
| 207 | mcountsym = ELF_R_SYM(_w(relp->r_info)); | 283 | mcountsym = Elf_r_sym(relp); |
| 208 | } | 284 | } |
| 209 | 285 | ||
| 210 | if (mcountsym == ELF_R_SYM(_w(relp->r_info))) { | 286 | if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { |
| 211 | uint_t const addend = _w(_w(relp->r_offset) - recval); | 287 | uint_t const addend = _w(_w(relp->r_offset) - recval); |
| 212 | 288 | ||
| 213 | mrelp->r_offset = _w(offbase | 289 | mrelp->r_offset = _w(offbase |
| 214 | + ((void *)mlocp - (void *)mloc0)); | 290 | + ((void *)mlocp - (void *)mloc0)); |
| 215 | mrelp->r_info = _w(ELF_R_INFO(recsym, reltype)); | 291 | Elf_r_info(mrelp, recsym, reltype); |
| 216 | if (sizeof(Elf_Rela) == rel_entsize) { | 292 | if (sizeof(Elf_Rela) == rel_entsize) { |
| 217 | ((Elf_Rela *)mrelp)->r_addend = addend; | 293 | ((Elf_Rela *)mrelp)->r_addend = addend; |
| 218 | *mlocp++ = 0; | 294 | *mlocp++ = 0; |
