diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 54504c5aa047..210b0c434064 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -42,29 +42,31 @@ want the address see %px below. 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 - For printing symbols and function pointers. The 'S' and 's' specifiers - result in the symbol name with ('S') or without ('s') offsets. Where - this is used on a kernel without KALLSYMS - the symbol address is - printed instead. + 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. + + 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. - On ia64, ppc64 and parisc64 architectures function pointers are - actually function descriptors which must first be resolved. The 'F' and - 'f' specifiers perform this resolution and then provide the same - functionality as the 'S' and 's' specifiers. - Kernel Pointers: %pK 01234567 or 0123456789abcdef diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index 93d790f7f4d8..a46649a1b605 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h @@ -8,6 +8,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) + \ @@ -21,6 +25,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/kernel/kallsyms.c b/kernel/kallsyms.c index edc9abd0eff1..6571beedd1c0 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,14 +19,11 @@ #include #include #include /* for cond_resched */ -#include #include #include #include #include -#include - /* * These will be re-linked against their real values * during the second link stage. @@ -51,37 +47,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/lib/vsprintf.c b/lib/vsprintf.c index 1c9b71fb1585..91dbb9b9e1df 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -41,7 +41,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 @@ -1731,10 +1730,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':