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

ARM: 9252/1: module: Teach unwinder about PLTs

"unwind: Index not found eef26358" warnings keep popping up on
CONFIG_ARM_MODULE_PLTS-enabled systems if the PC points to a PLT veneer.
Teach the unwinder how to deal with them, taking into account they don't
change state of the stack or register file except loading PC.

Link: https://lore.kernel.org/linux-arm-kernel/20200402153845.30985-1-kursad.oney@broadcom.com/

Tested-by: Kursad Oney <kursad.oney@broadcom.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>

authored by

Alex Sverdlin and committed by
Russell King (Oracle)
4ab07fd3 e66372ec

+31 -1
+5
arch/arm/include/asm/module.h
··· 37 37 38 38 struct module; 39 39 u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val); 40 + #ifdef CONFIG_ARM_MODULE_PLTS 41 + bool in_module_plt(unsigned long loc); 42 + #else 43 + static inline bool in_module_plt(unsigned long loc) { return false; } 44 + #endif 40 45 41 46 #ifdef CONFIG_THUMB2_KERNEL 42 47 #define HAVE_ARCH_KALLSYMS_SYMBOL_VALUE
+14
arch/arm/kernel/module-plts.c
··· 284 284 mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size); 285 285 return 0; 286 286 } 287 + 288 + bool in_module_plt(unsigned long loc) 289 + { 290 + struct module *mod; 291 + bool ret; 292 + 293 + preempt_disable(); 294 + mod = __module_text_address(loc); 295 + ret = mod && (loc - (u32)mod->arch.core.plt_ent < mod->arch.core.plt_count * PLT_ENT_SIZE || 296 + loc - (u32)mod->arch.init.plt_ent < mod->arch.init.plt_count * PLT_ENT_SIZE); 297 + preempt_enable(); 298 + 299 + return ret; 300 + }
+12 -1
arch/arm/kernel/unwind.c
··· 28 28 #include <linux/slab.h> 29 29 #include <linux/spinlock.h> 30 30 #include <linux/list.h> 31 + #include <linux/module.h> 31 32 32 33 #include <asm/stacktrace.h> 33 34 #include <asm/traps.h> ··· 396 395 397 396 idx = unwind_find_idx(frame->pc); 398 397 if (!idx) { 399 - if (frame->pc && kernel_text_address(frame->pc)) 398 + if (frame->pc && kernel_text_address(frame->pc)) { 399 + if (in_module_plt(frame->pc) && frame->pc != frame->lr) { 400 + /* 401 + * Quoting Ard: Veneers only set PC using a 402 + * PC+immediate LDR, and so they don't affect 403 + * the state of the stack or the register file 404 + */ 405 + frame->pc = frame->lr; 406 + return URC_OK; 407 + } 400 408 pr_warn("unwind: Index not found %08lx\n", frame->pc); 409 + } 401 410 return -URC_FAILURE; 402 411 } 403 412