diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-29 14:13:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-29 14:13:10 -0400 |
commit | b77d643ced576bdd1e918aebda869de74696cde9 (patch) | |
tree | bb5d708f4bbb48461923a28e63a8cf8bdd477dd7 /scripts | |
parent | b4020c1b198c0f0c0b0ff0cfdd824a26b93edd6f (diff) | |
parent | 64575f918f3279d8487cf670dbefa956ce16a526 (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus: (46 commits)
ftrace/MIPS: Enable C Version of recordmcount
ftrace/MIPS: Add module support for C version of recordmcount
ftrace/MIPS: Add MIPS64 support for C version of recordmcount
MIPS: Make TASK_SIZE reflect proper size for both 32 and 64 bit processes.
MIPS: Allow UserLocal on MIPS_R1 processors
MIPS: Honor L2 bypass bit
MIPS: Add BMIPS CP0 register definitions
MIPS: Add BMIPS processor types to Kconfig
MIPS: Decouple BMIPS CPU support from bcm47xx/bcm63xx SoC code
MIPS: Add support for hardware performance events (mipsxx)
MIPS: Perf-events: Add callchain support
MIPS: add support for hardware performance events (skeleton)
MIPS: add support for software performance events
MIPS: define local_xchg from xchg_local to atomic_long_xchg
MIPS: AR7: Add support for Titan (TNETV10xx) SoC variant
MIPS: AR7: Initialize GPIO earlier
MIPS: Add platform device and Kconfig for Octeon USB EHCI / OHCI
USB: Add EHCI and OHCH glue for OCTEON II SOCs.
MIPS: Octeon: Add register definitions for EHCI / OHCI USB glue logic.
MIPS: Octeon: Apply CN63XXP1 errata workarounds.
...
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/recordmcount.c | 44 | ||||
-rw-r--r-- | scripts/recordmcount.h | 86 |
2 files changed, 125 insertions, 5 deletions
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 26e1271259ba..f2f32eee2c5b 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c | |||
@@ -217,6 +217,39 @@ is_mcounted_section_name(char const *const txtname) | |||
217 | #define RECORD_MCOUNT_64 | 217 | #define RECORD_MCOUNT_64 |
218 | #include "recordmcount.h" | 218 | #include "recordmcount.h" |
219 | 219 | ||
220 | /* 64-bit EM_MIPS has weird ELF64_Rela.r_info. | ||
221 | * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf | ||
222 | * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40] | ||
223 | * to imply the order of the members; the spec does not say so. | ||
224 | * typedef unsigned char Elf64_Byte; | ||
225 | * fails on MIPS64 because their <elf.h> already has it! | ||
226 | */ | ||
227 | |||
228 | typedef uint8_t myElf64_Byte; /* Type for a 8-bit quantity. */ | ||
229 | |||
230 | union mips_r_info { | ||
231 | Elf64_Xword r_info; | ||
232 | struct { | ||
233 | Elf64_Word r_sym; /* Symbol index. */ | ||
234 | myElf64_Byte r_ssym; /* Special symbol. */ | ||
235 | myElf64_Byte r_type3; /* Third relocation. */ | ||
236 | myElf64_Byte r_type2; /* Second relocation. */ | ||
237 | myElf64_Byte r_type; /* First relocation. */ | ||
238 | } r_mips; | ||
239 | }; | ||
240 | |||
241 | static uint64_t MIPS64_r_sym(Elf64_Rel const *rp) | ||
242 | { | ||
243 | return w(((union mips_r_info){ .r_info = rp->r_info }).r_mips.r_sym); | ||
244 | } | ||
245 | |||
246 | static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type) | ||
247 | { | ||
248 | rp->r_info = ((union mips_r_info){ | ||
249 | .r_mips = { .r_sym = w(sym), .r_type = type } | ||
250 | }).r_info; | ||
251 | } | ||
252 | |||
220 | static void | 253 | static void |
221 | do_file(char const *const fname) | 254 | do_file(char const *const fname) |
222 | { | 255 | { |
@@ -268,6 +301,7 @@ do_file(char const *const fname) | |||
268 | case EM_386: reltype = R_386_32; break; | 301 | case EM_386: reltype = R_386_32; break; |
269 | case EM_ARM: reltype = R_ARM_ABS32; break; | 302 | case EM_ARM: reltype = R_ARM_ABS32; break; |
270 | case EM_IA_64: reltype = R_IA64_IMM64; gpfx = '_'; break; | 303 | case EM_IA_64: reltype = R_IA64_IMM64; gpfx = '_'; break; |
304 | case EM_MIPS: /* reltype: e_class */ gpfx = '_'; break; | ||
271 | case EM_PPC: reltype = R_PPC_ADDR32; gpfx = '_'; break; | 305 | case EM_PPC: reltype = R_PPC_ADDR32; gpfx = '_'; break; |
272 | case EM_PPC64: reltype = R_PPC64_ADDR64; gpfx = '_'; break; | 306 | case EM_PPC64: reltype = R_PPC64_ADDR64; gpfx = '_'; break; |
273 | case EM_S390: /* reltype: e_class */ gpfx = '_'; break; | 307 | case EM_S390: /* reltype: e_class */ gpfx = '_'; break; |
@@ -291,6 +325,10 @@ do_file(char const *const fname) | |||
291 | } | 325 | } |
292 | if (EM_S390 == w2(ehdr->e_machine)) | 326 | if (EM_S390 == w2(ehdr->e_machine)) |
293 | reltype = R_390_32; | 327 | reltype = R_390_32; |
328 | if (EM_MIPS == w2(ehdr->e_machine)) { | ||
329 | reltype = R_MIPS_32; | ||
330 | is_fake_mcount32 = MIPS32_is_fake_mcount; | ||
331 | } | ||
294 | do32(ehdr, fname, reltype); | 332 | do32(ehdr, fname, reltype); |
295 | } break; | 333 | } break; |
296 | case ELFCLASS64: { | 334 | case ELFCLASS64: { |
@@ -303,6 +341,12 @@ do_file(char const *const fname) | |||
303 | } | 341 | } |
304 | if (EM_S390 == w2(ghdr->e_machine)) | 342 | if (EM_S390 == w2(ghdr->e_machine)) |
305 | reltype = R_390_64; | 343 | reltype = R_390_64; |
344 | if (EM_MIPS == w2(ghdr->e_machine)) { | ||
345 | reltype = R_MIPS_64; | ||
346 | Elf64_r_sym = MIPS64_r_sym; | ||
347 | Elf64_r_info = MIPS64_r_info; | ||
348 | is_fake_mcount64 = MIPS64_is_fake_mcount; | ||
349 | } | ||
306 | do64(ghdr, fname, reltype); | 350 | do64(ghdr, fname, reltype); |
307 | } break; | 351 | } break; |
308 | } /* end switch */ | 352 | } /* end switch */ |
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; |