diff options
author | Tony Wu <tung7970@gmail.com> | 2013-05-12 11:05:34 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2013-05-17 14:59:35 -0400 |
commit | 5000653e923de49aa282fd7d172eb6528c3ec5c7 (patch) | |
tree | 8281f7a92a93c4b44af76b47c159c136905130e6 /arch/mips | |
parent | e7438c4b893e87311d2fb0facb3e6a0df17abe01 (diff) |
MIPS: Extract schedule_mfi info from __schedule
schedule_mfi is supposed to be extracted from schedule(), and
is used in thread_saved_pc and get_wchan.
But, after optimization, schedule() is reduced to a sibling
call to __schedule(), and no real frame info can be extracted.
One solution is to compile schedule() with -fno-omit-frame-pointer
and -fno-optimize-sibling-calls, but that will incur performance
degradation.
Another solution is to extract info from the real scheduler,
__schedule, and this is the approache adopted here.
This patch reads the __schedule address by either following
the 'j' call in schedule if KALLSYMS is disabled or by using
kallsyms_lookup_name to lookup __schedule if KALLSYMS is
available, then, extracts schedule_mfi from __schedule frame info.
This patch also fixes the "Can't analyze schedule() prologue"
warning at boot time.
Signed-off-by: Tony Wu <tung7970@gmail.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/5237/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/kernel/process.c | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 785bf2a4129a..a682a87bcc04 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -224,6 +224,9 @@ struct mips_frame_info { | |||
224 | int pc_offset; | 224 | int pc_offset; |
225 | }; | 225 | }; |
226 | 226 | ||
227 | #define J_TARGET(pc,target) \ | ||
228 | (((unsigned long)(pc) & 0xf0000000) | ((target) << 2)) | ||
229 | |||
227 | static inline int is_ra_save_ins(union mips_instruction *ip) | 230 | static inline int is_ra_save_ins(union mips_instruction *ip) |
228 | { | 231 | { |
229 | #ifdef CONFIG_CPU_MICROMIPS | 232 | #ifdef CONFIG_CPU_MICROMIPS |
@@ -395,15 +398,42 @@ err: | |||
395 | 398 | ||
396 | static struct mips_frame_info schedule_mfi __read_mostly; | 399 | static struct mips_frame_info schedule_mfi __read_mostly; |
397 | 400 | ||
401 | #ifdef CONFIG_KALLSYMS | ||
402 | static unsigned long get___schedule_addr(void) | ||
403 | { | ||
404 | return kallsyms_lookup_name("__schedule"); | ||
405 | } | ||
406 | #else | ||
407 | static unsigned long get___schedule_addr(void) | ||
408 | { | ||
409 | union mips_instruction *ip = (void *)schedule; | ||
410 | int max_insns = 8; | ||
411 | int i; | ||
412 | |||
413 | for (i = 0; i < max_insns; i++, ip++) { | ||
414 | if (ip->j_format.opcode == j_op) | ||
415 | return J_TARGET(ip, ip->j_format.target); | ||
416 | } | ||
417 | return 0; | ||
418 | } | ||
419 | #endif | ||
420 | |||
398 | static int __init frame_info_init(void) | 421 | static int __init frame_info_init(void) |
399 | { | 422 | { |
400 | unsigned long size = 0; | 423 | unsigned long size = 0; |
401 | #ifdef CONFIG_KALLSYMS | 424 | #ifdef CONFIG_KALLSYMS |
402 | unsigned long ofs; | 425 | unsigned long ofs; |
426 | #endif | ||
427 | unsigned long addr; | ||
403 | 428 | ||
404 | kallsyms_lookup_size_offset((unsigned long)schedule, &size, &ofs); | 429 | addr = get___schedule_addr(); |
430 | if (!addr) | ||
431 | addr = (unsigned long)schedule; | ||
432 | |||
433 | #ifdef CONFIG_KALLSYMS | ||
434 | kallsyms_lookup_size_offset(addr, &size, &ofs); | ||
405 | #endif | 435 | #endif |
406 | schedule_mfi.func = schedule; | 436 | schedule_mfi.func = (void *)addr; |
407 | schedule_mfi.func_size = size; | 437 | schedule_mfi.func_size = size; |
408 | 438 | ||
409 | get_frame_info(&schedule_mfi); | 439 | get_frame_info(&schedule_mfi); |