diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 361789df51ecf58d5083436792588d2f12faa7f2..58c44cce90b662c7a96772fce4ad971a4130d7cb 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -50,42 +50,31 @@ Symbols/Function Pointers :: + %pS versatile_init+0x0/0x110 + %ps versatile_init %pF versatile_init+0x0/0x110 %pf versatile_init - %pS versatile_init+0x0/0x110 %pSR versatile_init+0x9/0x110 (with __builtin_extract_return_addr() translation) - %ps versatile_init %pB prev_fn_of_versatile_init+0x88/0x88 -The ``F`` and ``f`` specifiers are for printing function pointers, -for example, f->func, &gettimeofday. They have the same result as -``S`` and ``s`` specifiers. But they do an extra conversion on -ia64, ppc64 and parisc64 architectures where the function pointers -are actually function descriptors. +The ``S`` and ``s`` specifiers are used for printing a pointer in symbolic +format. They result in the symbol name with (``S``) or without (``s``) +offsets. If KALLSYMS are disabled then the symbol address is printed instead. -The ``S`` and ``s`` specifiers can be used for printing symbols -from direct addresses, for example, __builtin_return_address(0), -(void *)regs->ip. They result in the symbol name with (``S``) or -without (``s``) offsets. If KALLSYMS are disabled then the symbol -address is printed instead. +Note, that the ``F`` and ``f`` specifiers are identical to ``S`` (``s``) +and thus deprecated. We have ``F`` and ``f`` because on ia64, ppc64 and +parisc64 function pointers are indirect and, in fact, are function +descriptors, which require additional dereferencing before we can lookup +the symbol. As of now, ``S`` and ``s`` perform dereferencing on those +platforms (when needed), so ``F`` and ``f`` exist for compatibility +reasons only. The ``B`` specifier results in the symbol name with offsets and should be used when printing stack backtraces. The specifier takes into consideration the effect of compiler optimisations which may occur when tail-call``s are used and marked with the noreturn GCC attribute. -Examples:: - - printk("Going to call: %pF\n", gettimeofday); - printk("Going to call: %pF\n", p->func); - printk("%s: called from %pS\n", __func__, (void *)_RET_IP_); - printk("%s: called from %pS\n", __func__, - (void *)__builtin_return_address(0)); - printk("Faulted at %pS\n", (void *)regs->ip); - printk(" %s%pB\n", (reliable ? "" : "? "), (void *)*stack); - - Kernel Pointers =============== diff --git a/arch/ia64/include/asm/sections.h b/arch/ia64/include/asm/sections.h index f3481408594e029b5bbac1c1cd117384ae07725c..cea15f2dd38df7556bd054fdf18024ccaac29608 100644 --- a/arch/ia64/include/asm/sections.h +++ b/arch/ia64/include/asm/sections.h @@ -27,6 +27,8 @@ extern char __start_gate_brl_fsys_bubble_down_patchlist[], __end_gate_brl_fsys_b extern char __start_unwind[], __end_unwind[]; extern char __start_ivt_text[], __end_ivt_text[]; +#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1 + #undef dereference_function_descriptor static inline void *dereference_function_descriptor(void *ptr) { @@ -38,6 +40,12 @@ static inline void *dereference_function_descriptor(void *ptr) return ptr; } +#undef dereference_kernel_function_descriptor +static inline void *dereference_kernel_function_descriptor(void *ptr) +{ + if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd) + return ptr; + return dereference_function_descriptor(ptr); +} #endif /* _ASM_IA64_SECTIONS_H */ - diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 853b5611a894d5a2770606f983782ea1a9a6dbc5..326448f9df16068392e49af096afd1c8b2713131 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -36,6 +36,7 @@ #include #include +#include #define ARCH_MODULE_DEBUG 0 @@ -918,3 +919,14 @@ module_arch_cleanup (struct module *mod) if (mod->arch.core_unw_table) unw_remove_unwind_table(mod->arch.core_unw_table); } + +void *dereference_module_function_descriptor(struct module *mod, void *ptr) +{ + Elf64_Shdr *opd = mod->arch.opd; + + if (ptr < (void *)opd->sh_addr || + ptr >= (void *)(opd->sh_addr + opd->sh_size)) + return ptr; + + return dereference_function_descriptor(ptr); +} diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 58db59da0bd87042c8d0d457a77268f7b043e40f..31e688981b4b7b4945428e1167b351c4ac578800 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -108,7 +108,9 @@ SECTIONS { RODATA .opd : AT(ADDR(.opd) - LOAD_OFFSET) { + __start_opd = .; *(.opd) + __end_opd = .; } /* diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index 4085d72fa5ae8a30bc3011f3e8cf44ca331568d5..5fb6d512502d807426520a2b2b37c7ca403d5ae8 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -39,8 +39,7 @@ #include #include #include - -extern char _etext, _stext; +#include int kstack_depth_to_print = 0x180; int lwa_flag; diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S index a4ce3314e78e04a1e47ac977234eee5f731248f2..4ebd4e65524cd3cf6347a2948dede9163a4807b9 100644 --- a/arch/parisc/boot/compressed/vmlinux.lds.S +++ b/arch/parisc/boot/compressed/vmlinux.lds.S @@ -29,7 +29,9 @@ SECTIONS . = ALIGN(16); /* Linkage tables */ .opd : { + __start_opd = .; *(.opd) + __end_opd = .; } PROVIDE (__gp = .); .plt : { *(.plt) diff --git a/arch/parisc/include/asm/sections.h b/arch/parisc/include/asm/sections.h index accdf40aa5b7402396a40be069d6c84e04981a69..5a40b51df80ce1f6f5cb331975ca273575db622e 100644 --- a/arch/parisc/include/asm/sections.h +++ b/arch/parisc/include/asm/sections.h @@ -6,8 +6,14 @@ #include #ifdef CONFIG_64BIT + +#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1 + #undef dereference_function_descriptor void *dereference_function_descriptor(void *); + +#undef dereference_kernel_function_descriptor +void *dereference_kernel_function_descriptor(void *); #endif #endif diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index f1a76935a3149495c8a65faeee8028295c24e559..b5b3cb00f1fb0f4cb2368812c461a9821350c48f 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -66,6 +66,7 @@ #include #include +#include #if 0 #define DEBUGP printk @@ -954,3 +955,18 @@ void module_arch_cleanup(struct module *mod) { deregister_unwind_table(mod); } + +#ifdef CONFIG_64BIT +void *dereference_module_function_descriptor(struct module *mod, void *ptr) +{ + unsigned long start_opd = (Elf64_Addr)mod->core_layout.base + + mod->arch.fdesc_offset; + unsigned long end_opd = start_opd + + mod->arch.fdesc_count * sizeof(Elf64_Fdesc); + + if (ptr < (void *)start_opd || ptr >= (void *)end_opd) + return ptr; + + return dereference_function_descriptor(ptr); +} +#endif diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 30f92391a93ef6d5a90970b81921a2133d5e2eb0..6c4585103a912e52babe30258f52d2a56223f7b9 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -276,6 +276,15 @@ void *dereference_function_descriptor(void *ptr) ptr = p; return ptr; } + +void *dereference_kernel_function_descriptor(void *ptr) +{ + if (ptr < (void *)__start_opd || + ptr >= (void *)__end_opd) + return ptr; + + return dereference_function_descriptor(ptr); +} #endif static inline unsigned long brk_rnd(void) diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 159a2ec0b4e01f148c1ed6e4c5539abb504ac1b6..da2e31190efa1b98f4975c0be5e4c633e4bc6e87 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -100,7 +100,9 @@ SECTIONS . = ALIGN(16); /* Linkage tables */ .opd : { + __start_opd = .; *(.opd) + __end_opd = .; } PROVIDE (__gp = .); .plt : { *(.plt) diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index 6c0132c7212f8ea484805c9a9f72b682b79f6a39..7e28442827f1e6feb966c4aeeabd3961e4cb360f 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h @@ -45,6 +45,9 @@ struct mod_arch_specific { unsigned long tramp; #endif + /* For module function descriptor dereference */ + unsigned long start_opd; + unsigned long end_opd; #else /* powerpc64 */ /* Indices of PLT sections within module. */ unsigned int core_plt_section; diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h index 82bec63bbd4f214a43b8f6094d55bb9cbbe7e376..e335a8f846afdd0d8388e782b02c5dba563bf206 100644 --- a/arch/powerpc/include/asm/sections.h +++ b/arch/powerpc/include/asm/sections.h @@ -66,6 +66,9 @@ static inline int overlaps_kvm_tmp(unsigned long start, unsigned long end) } #ifdef PPC64_ELF_ABI_v1 + +#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1 + #undef dereference_function_descriptor static inline void *dereference_function_descriptor(void *ptr) { @@ -76,6 +79,15 @@ static inline void *dereference_function_descriptor(void *ptr) ptr = p; return ptr; } + +#undef dereference_kernel_function_descriptor +static inline void *dereference_kernel_function_descriptor(void *ptr) +{ + if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd) + return ptr; + + return dereference_function_descriptor(ptr); +} #endif /* PPC64_ELF_ABI_v1 */ #endif diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 759104b99f9feb5940d186d0402ab5622e7ca347..218971ac7e04c72499aa3dbb020fa490a091463d 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -93,6 +93,15 @@ static unsigned int local_entry_offset(const Elf64_Sym *sym) { return 0; } + +void *dereference_module_function_descriptor(struct module *mod, void *ptr) +{ + if (ptr < (void *)mod->arch.start_opd || + ptr >= (void *)mod->arch.end_opd) + return ptr; + + return dereference_function_descriptor(ptr); +} #endif #define STUB_MAGIC 0x73747562 /* stub */ @@ -344,6 +353,11 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0) dedotify_versions((void *)hdr + sechdrs[i].sh_offset, sechdrs[i].sh_size); + else if (!strcmp(secstrings + sechdrs[i].sh_name, ".opd")) { + me->arch.start_opd = sechdrs[i].sh_addr; + me->arch.end_opd = sechdrs[i].sh_addr + + sechdrs[i].sh_size; + } /* We don't handle .init for the moment: rename to _init */ while ((p = strstr(secstrings + sechdrs[i].sh_name, ".init"))) diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 0494e1566ee2ab9b976cb0d9edb8c195a4490a23..5dac5ab22fa2898a57bb3b21181221c4ed14dcc6 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -278,7 +278,9 @@ SECTIONS } .opd : AT(ADDR(.opd) - LOAD_OFFSET) { + __start_opd = .; *(.opd) + __end_opd = .; } . = ALIGN(256); diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 03cc5f9bba71c135f98d804640a9a8c4f2598c65..849cd8eb5ca0650c46e51f1848302ced07533757 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -30,6 +30,7 @@ * __ctors_start, __ctors_end * __irqentry_text_start, __irqentry_text_end * __softirqentry_text_start, __softirqentry_text_end + * __start_opd, __end_opd */ extern char _text[], _stext[], _etext[]; extern char _data[], _sdata[], _edata[]; @@ -49,12 +50,15 @@ extern char __start_once[], __end_once[]; /* Start and end of .ctors section - used for constructor calls. */ extern char __ctors_start[], __ctors_end[]; +/* Start and end of .opd section - used for function descriptors. */ +extern char __start_opd[], __end_opd[]; + extern __visible const void __nosave_begin, __nosave_end; -/* function descriptor handling (if any). Override - * in asm/sections.h */ +/* Function descriptor handling (if any). Override in asm/sections.h */ #ifndef dereference_function_descriptor #define dereference_function_descriptor(p) (p) +#define dereference_kernel_function_descriptor(p) (p) #endif /* random extra sections (if any). Override diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index 708f337d780be3ee4c628fe0422e3a6752d0fb33..e4f2e5a65f14fb6dc2b09125b59bd3e6767c5674 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h @@ -9,6 +9,10 @@ #include #include #include +#include +#include + +#include #define KSYM_NAME_LEN 128 #define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \ @@ -22,6 +26,56 @@ struct module; +static inline int is_kernel_inittext(unsigned long addr) +{ + if (addr >= (unsigned long)_sinittext + && addr <= (unsigned long)_einittext) + return 1; + return 0; +} + +static inline int is_kernel_text(unsigned long addr) +{ + if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) || + arch_is_kernel_text(addr)) + return 1; + return in_gate_area_no_mm(addr); +} + +static inline int is_kernel(unsigned long addr) +{ + if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end) + return 1; + return in_gate_area_no_mm(addr); +} + +static inline int is_ksym_addr(unsigned long addr) +{ + if (IS_ENABLED(CONFIG_KALLSYMS_ALL)) + return is_kernel(addr); + + return is_kernel_text(addr) || is_kernel_inittext(addr); +} + +static inline void *dereference_symbol_descriptor(void *ptr) +{ +#ifdef HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR + struct module *mod; + + ptr = dereference_kernel_function_descriptor(ptr); + if (is_ksym_addr((unsigned long)ptr)) + return ptr; + + preempt_disable(); + mod = __module_address((unsigned long)ptr); + preempt_enable(); + + if (mod) + ptr = dereference_module_function_descriptor(mod, ptr); +#endif + return ptr; +} + #ifdef CONFIG_KALLSYMS /* Lookup the address for a symbol. Returns 0 if not found. */ unsigned long kallsyms_lookup_name(const char *name); diff --git a/include/linux/module.h b/include/linux/module.h index c69b49abe8775417587387a8d7def5497e476fc8..e6249795f9e2c2015a6fd20a9d4b8e98456c5d02 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -606,6 +606,9 @@ int ref_module(struct module *a, struct module *b); __mod ? __mod->name : "kernel"; \ }) +/* Dereference module function descriptor */ +void *dereference_module_function_descriptor(struct module *mod, void *ptr); + /* For kallsyms to ask for address resolution. namebuf should be at * least KSYM_NAME_LEN long: a pointer to namebuf is returned if * found, otherwise NULL. */ @@ -760,6 +763,13 @@ static inline bool is_module_sig_enforced(void) return false; } +/* Dereference module function descriptor */ +static inline +void *dereference_module_function_descriptor(struct module *mod, void *ptr) +{ + return ptr; +} + #endif /* CONFIG_MODULES */ #ifdef CONFIG_SYSFS diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 531ffa984bc262716b3412f5cfc2476c448d379f..0e4c0922908a3d82085896ed8a04f1651d639c71 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -12,7 +12,6 @@ * compression (see scripts/kallsyms.c for a more complete description) */ #include -#include #include #include #include @@ -20,15 +19,12 @@ #include #include #include /* for cond_resched */ -#include #include #include #include #include #include -#include - /* * These will be re-linked against their real values * during the second link stage. @@ -52,37 +48,6 @@ extern const u16 kallsyms_token_index[] __weak; extern const unsigned long kallsyms_markers[] __weak; -static inline int is_kernel_inittext(unsigned long addr) -{ - if (addr >= (unsigned long)_sinittext - && addr <= (unsigned long)_einittext) - return 1; - return 0; -} - -static inline int is_kernel_text(unsigned long addr) -{ - if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) || - arch_is_kernel_text(addr)) - return 1; - return in_gate_area_no_mm(addr); -} - -static inline int is_kernel(unsigned long addr) -{ - if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end) - return 1; - return in_gate_area_no_mm(addr); -} - -static int is_ksym_addr(unsigned long addr) -{ - if (IS_ENABLED(CONFIG_KALLSYMS_ALL)) - return is_kernel(addr); - - return is_kernel_text(addr) || is_kernel_inittext(addr); -} - /* * Expand a compressed symbol data into the resulting uncompressed string, * if uncompressed string is too long (>= maxlen), it will be truncated, diff --git a/kernel/module.c b/kernel/module.c index f0411a27176552a2a172c534a84c37e10c76705d..65f6561d70e1fc3a40f11867edff6d90ae986d15 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3938,6 +3938,12 @@ static const char *get_ksymbol(struct module *mod, return symname(kallsyms, best); } +void * __weak dereference_module_function_descriptor(struct module *mod, + void *ptr) +{ + return ptr; +} + /* For kallsyms to ask for address resolution. NULL means not found. Careful * not to lock to avoid deadlock on oopses, simply disable preemption. */ const char *module_address_lookup(unsigned long addr, diff --git a/kernel/sched/autogroup.c b/kernel/sched/autogroup.c index a43df51935386fcd48f9fad8905d722880c8f8c8..bb4b9fe026a15da65dad6a7d83108fc5f4585715 100644 --- a/kernel/sched/autogroup.c +++ b/kernel/sched/autogroup.c @@ -1,13 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include "sched.h" - #include #include -#include #include #include #include +#include "sched.h" + unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1; static struct autogroup autogroup_default; static atomic_t autogroup_seq_nr; diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 1746bae94d416f6ce3311c569e5d99080173f998..16e2eefb0f799f66a9e195331bc9e35323df5541 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -40,7 +40,6 @@ #include "../mm/internal.h" /* For the trace_print_flags arrays */ #include /* for PAGE_SIZE */ -#include /* for dereference_function_descriptor() */ #include /* cpu_to_le16 */ #include @@ -1723,10 +1722,10 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, switch (*fmt) { case 'F': case 'f': - ptr = dereference_function_descriptor(ptr); - /* Fallthrough */ case 'S': case 's': + ptr = dereference_symbol_descriptor(ptr); + /* Fallthrough */ case 'B': return symbol_string(buf, end, ptr, spec, fmt); case 'R': diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 95cda3ecc66b859ec1c86762810bfbd200687ef0..0bb68e7ff1734d3b1388ac095935deee59c25a05 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -5753,18 +5753,25 @@ sub process { for (my $count = $linenr; $count <= $lc; $count++) { my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); $fmt =~ s/%%//g; - if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) { + if ($fmt =~ /(\%[\*\d\.]*p(?![\WSsBKRraEhMmIiUDdgVCbGNO]).)/) { $bad_extension = $1; last; } } if ($bad_extension ne "") { my $stat_real = raw_line($linenr, 0); + my $ext_type = "Invalid"; + my $use = ""; for (my $count = $linenr + 1; $count <= $lc; $count++) { $stat_real = $stat_real . "\n" . raw_line($count, 0); } + if ($bad_extension =~ /p[Ff]/) { + $ext_type = "Deprecated"; + $use = " - use %pS instead"; + $use =~ s/pS/ps/ if ($bad_extension =~ /pf/); + } WARN("VSPRINTF_POINTER_EXTENSION", - "Invalid vsprintf pointer extension '$bad_extension'\n" . "$here\n$stat_real\n"); + "$ext_type vsprintf pointer extension '$bad_extension'$use\n" . "$here\n$stat_real\n"); } }