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. This patch follows the sibling call and extracts the schedule_mfi from the __schedule with and without KALLSYMS enabled. Signed-off-by: Tony Wu <tung7970@xxxxxxxxx> --- arch/mips/kernel/process.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index a794eb5..289ea69 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -314,15 +314,39 @@ err: static struct mips_frame_info schedule_mfi __read_mostly; +static unsigned long get___schedule_addr(void) +{ +#ifdef CONFIG_KALLSYMS + return kallsyms_lookup_name("__schedule"); +#else + union mips_instruction *ip = (void *)schedule; + int max_insns = 8; + int i; + + for (i = 0; i < max_insns; i++, ip++) { + if (ip->j_format.opcode == j_op) + return J_TARGET(ip, ip->j_format.target); + } + return 0; +#endif +} + static int __init frame_info_init(void) { unsigned long size = 0; #ifdef CONFIG_KALLSYMS unsigned long ofs; +#endif + unsigned long addr; + + addr = get___schedule_addr(); + if (!addr) + addr = (unsigned long)schedule; - kallsyms_lookup_size_offset((unsigned long)schedule, &size, &ofs); +#ifdef CONFIG_KALLSYMS + kallsyms_lookup_size_offset(addr, &size, &ofs); #endif - schedule_mfi.func = schedule; + schedule_mfi.func = (void *)addr; schedule_mfi.func_size = size; get_frame_info(&schedule_mfi); -- 1.7.10.2 (Apple Git-33)