Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Tony Wu and committed by
Ralf Baechle
5000653e e7438c4b

+33 -3
+33 -3
arch/mips/kernel/process.c
··· 224 224 int pc_offset; 225 225 }; 226 226 227 + #define J_TARGET(pc,target) \ 228 + (((unsigned long)(pc) & 0xf0000000) | ((target) << 2)) 229 + 227 230 static inline int is_ra_save_ins(union mips_instruction *ip) 228 231 { 229 232 #ifdef CONFIG_CPU_MICROMIPS ··· 398 395 399 396 static struct mips_frame_info schedule_mfi __read_mostly; 400 397 398 + #ifdef CONFIG_KALLSYMS 399 + static unsigned long get___schedule_addr(void) 400 + { 401 + return kallsyms_lookup_name("__schedule"); 402 + } 403 + #else 404 + static unsigned long get___schedule_addr(void) 405 + { 406 + union mips_instruction *ip = (void *)schedule; 407 + int max_insns = 8; 408 + int i; 409 + 410 + for (i = 0; i < max_insns; i++, ip++) { 411 + if (ip->j_format.opcode == j_op) 412 + return J_TARGET(ip, ip->j_format.target); 413 + } 414 + return 0; 415 + } 416 + #endif 417 + 401 418 static int __init frame_info_init(void) 402 419 { 403 420 unsigned long size = 0; 404 421 #ifdef CONFIG_KALLSYMS 405 422 unsigned long ofs; 406 - 407 - kallsyms_lookup_size_offset((unsigned long)schedule, &size, &ofs); 408 423 #endif 409 - schedule_mfi.func = schedule; 424 + unsigned long addr; 425 + 426 + addr = get___schedule_addr(); 427 + if (!addr) 428 + addr = (unsigned long)schedule; 429 + 430 + #ifdef CONFIG_KALLSYMS 431 + kallsyms_lookup_size_offset(addr, &size, &ofs); 432 + #endif 433 + schedule_mfi.func = (void *)addr; 410 434 schedule_mfi.func_size = size; 411 435 412 436 get_frame_info(&schedule_mfi);