diff mbox series

[PATCHv4,5/6] symbol lookup: introduce dereference_symbol_descriptor()

Message ID 20171109234830.5067-6-sergey.senozhatsky@gmail.com (mailing list archive)
State Not Applicable
Headers show
Series printk/ia64/ppc64/parisc64: let's deprecate %pF/%pf printk specifiers | expand

Commit Message

Sergey Senozhatsky Nov. 9, 2017, 11:48 p.m. UTC
dereference_symbol_descriptor() invokes appropriate ARCH specific
function descriptor dereference callbacks:
- dereference_kernel_function_descriptor() if the pointer is a
  kernel symbol;

- dereference_module_function_descriptor() if the pointer is a
  module symbol.

This is the last step needed to make '%pS/%ps' smart enough to
handle function descriptor dereference on affected ARCHs and
to retire '%pF/%pf'.

To refresh it:
  Some architectures (ia64, ppc64, parisc64) use an indirect pointer
  for C function pointers - the function pointer points to a function
  descriptor and we need to dereference it to get the actual function
  pointer.

  Function descriptors live in .opd elf section and all affected
  ARCHs (ia64, ppc64, parisc64) handle it properly for kernel and
  modules. So we, technically, can decide if the dereference is
  needed by simply looking at the pointer: if it belongs to .opd
  section then we need to dereference it.

  The kernel and modules have their own .opd sections, obviously,
  that's why we need to split dereference_function_descriptor()
  and use separate kernel and module dereference arch callbacks.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
 Documentation/printk-formats.txt | 49 ++++++++++++++++------------------------
 include/linux/kallsyms.h         |  2 ++
 kernel/kallsyms.c                | 19 ++++++++++++++++
 lib/vsprintf.c                   |  5 ++--
 4 files changed, 42 insertions(+), 33 deletions(-)

Comments

Luck, Tony Nov. 10, 2017, 6:09 p.m. UTC | #1
On Fri, Nov 10, 2017 at 08:48:29AM +0900, Sergey Senozhatsky wrote:
> -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);

Did you mean to delete the Examples completely?  Wouldn't it
be better to just update (s/%pF/%pS/g)?

-Tony
Sergey Senozhatsky Nov. 11, 2017, 4:49 a.m. UTC | #2
On (11/10/17 10:09), Luck, Tony wrote:
> On Fri, Nov 10, 2017 at 08:48:29AM +0900, Sergey Senozhatsky wrote:
> > -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);
> 
> Did you mean to delete the Examples completely?  Wouldn't it
> be better to just update (s/%pF/%pS/g)?

good question. yes, I think I did it deliberately :) we still
kinda have some sort of "examples", right at the beginning of
section "Symbols/Function Pointers"


>  Symbols/Function Pointers
>  =========================
>
>  ::
>
>         %pS     versatile_init+0x0/0x110
>          %ps     versatile_init
>          %pF     versatile_init+0x0/0x110
>          %pf     versatile_init
>          %pSR    versatile_init+0x9/0x110
>                 (with __builtin_extract_return_addr() translation)
>          %pB     prev_fn_of_versatile_init+0x88/0x88
>
>  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.

I can return Examples back. don't really have a strong opinion
on this. let me know.

	-ss
Petr Mladek Nov. 28, 2017, 3:44 p.m. UTC | #3
On Sat 2017-11-11 13:49:32, Sergey Senozhatsky wrote:
> On (11/10/17 10:09), Luck, Tony wrote:
> > On Fri, Nov 10, 2017 at 08:48:29AM +0900, Sergey Senozhatsky wrote:
> > > -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);
> > 
> > Did you mean to delete the Examples completely?  Wouldn't it
> > be better to just update (s/%pF/%pS/g)?
> 
> good question. yes, I think I did it deliberately :) we still
> kinda have some sort of "examples", right at the beginning of
> section "Symbols/Function Pointers"

These extra examples were added just recently (v4.14-rc1)
by the commit fd46cd55fbc5a8e8c ("printk-formats.txt: Add examples
for %pF and %pS usage"). They were supposed to help using
%pF and %pS correctly according to the situation. But we
have a better solution now. %pF is obsoleted by this
patchset.

IMHO, it is perfectly fine to remove the extra examples.

Best Regards,
Petr
Sergey Senozhatsky Dec. 6, 2017, 4:36 a.m. UTC | #4
Hello,

	so we got a number of build-error reports [somehow I
thought 0day has compile tested the patches already; well, I
was wrong] basically on congifs that have no KALLSYMS.


Petr, can we replace 0006 with the following patch?

8<--- --- ---

From: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Subject: [PATCH] symbol lookup: introduce dereference_symbol_descriptor()

dereference_symbol_descriptor() invokes appropriate ARCH specific
function descriptor dereference callbacks:
- dereference_kernel_function_descriptor() if the pointer is a
  kernel symbol;

- dereference_module_function_descriptor() if the pointer is a
  module symbol.

This is the last step needed to make '%pS/%ps' smart enough to
handle function descriptor dereference on affected ARCHs and
to retire '%pF/%pf'.

To refresh it:
  Some architectures (ia64, ppc64, parisc64) use an indirect pointer
  for C function pointers - the function pointer points to a function
  descriptor and we need to dereference it to get the actual function
  pointer.

  Function descriptors live in .opd elf section and all affected
  ARCHs (ia64, ppc64, parisc64) handle it properly for kernel and
  modules. So we, technically, can decide if the dereference is
  needed by simply looking at the pointer: if it belongs to .opd
  section then we need to dereference it.

  The kernel and modules have their own .opd sections, obviously,
  that's why we need to split dereference_function_descriptor()
  and use separate kernel and module dereference arch callbacks.

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
 Documentation/printk-formats.txt | 42 ++++++++++++-------------------
 include/linux/kallsyms.h         | 53 ++++++++++++++++++++++++++++++++++++++++
 kernel/kallsyms.c                | 33 -------------------------
 lib/vsprintf.c                   |  5 ++--
 4 files changed, 71 insertions(+), 62 deletions(-)

diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index aa0a776c817a..02745028e909 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -61,41 +61,31 @@ Symbols/Function Pointers
 
 ::
 
-	%pF	versatile_init+0x0/0x110
-	%pf	versatile_init
-	%pS	versatile_init+0x0/0x110
-	%pSR	versatile_init+0x9/0x110
+	%pS     versatile_init+0x0/0x110
+	%ps     versatile_init
+	%pF     versatile_init+0x0/0x110
+	%pf     versatile_init
+	%pSR    versatile_init+0x9/0x110
 		(with __builtin_extract_return_addr() translation)
-	%ps	versatile_init
-	%pB	prev_fn_of_versatile_init+0x88/0x88
+	%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/include/linux/kallsyms.h b/include/linux/kallsyms.h
index bd118a6c60cb..1bcfe221e62c 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -9,6 +9,9 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
+#include <linux/mm.h>
+
+#include <asm/sections.h>
 
 #define KSYM_NAME_LEN 128
 #define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
@@ -16,6 +19,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 d5fa4116688a..4a79598e92c7 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -27,8 +27,6 @@
 #include <linux/ftrace.h>
 #include <linux/compiler.h>
 
-#include <asm/sections.h>
-
 /*
  * These will be re-linked against their real values
  * during the second link stage.
@@ -52,37 +50,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 01c3957b2de6..03950269f35d 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -42,7 +42,6 @@
 #include "../mm/internal.h"	/* For the trace_print_flags arrays */
 
 #include <asm/page.h>		/* for PAGE_SIZE */
-#include <asm/sections.h>	/* for dereference_function_descriptor() */
 #include <asm/byteorder.h>	/* cpu_to_le16 */
 
 #include <linux/string_helpers.h>
@@ -1862,10 +1861,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':
Petr Mladek Dec. 6, 2017, 10:32 a.m. UTC | #5
On Wed 2017-12-06 13:36:49, Sergey Senozhatsky wrote:
> Hello,
> 
> 	so we got a number of build-error reports [somehow I
> thought 0day has compile tested the patches already; well, I
> was wrong] basically on congifs that have no KALLSYMS.
> 
> 
> Petr, can we replace 0006 with the following patch?

Done. See comments below.

> From: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
> Subject: [PATCH] symbol lookup: introduce dereference_symbol_descriptor()
> 
> 
> Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>

The new patch only shuffled the code to fix a compilation problem
with CONFIG_CALLSYMS undefined. It did not change the functionality.
Therefore I put back:

Tested-by: Tony Luck <tony.luck@intel.com> #ia64
Tested-by: Santosh Sivaraj <santosh@fossix.org> #powerpc
Tested-by: Helge Deller <deller@gmx.de> #parisc64

> ---
>  Documentation/printk-formats.txt | 42 ++++++++++++-------------------
>  include/linux/kallsyms.h         | 53 ++++++++++++++++++++++++++++++++++++++++
>  kernel/kallsyms.c                | 33 -------------------------
>  lib/vsprintf.c                   |  5 ++--
>  4 files changed, 71 insertions(+), 62 deletions(-)
> 
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index aa0a776c817a..02745028e909 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -61,41 +61,31 @@ Symbols/Function Pointers
>  
>  ::
>  
> -	%pF	versatile_init+0x0/0x110
> -	%pf	versatile_init
> -	%pS	versatile_init+0x0/0x110
> -	%pSR	versatile_init+0x9/0x110
> +	%pS     versatile_init+0x0/0x110
> +	%ps     versatile_init
> +	%pF     versatile_init+0x0/0x110
> +	%pf     versatile_init
> +	%pSR    versatile_init+0x9/0x110
>  		(with __builtin_extract_return_addr() translation)
> -	%ps	versatile_init
> -	%pB	prev_fn_of_versatile_init+0x88/0x88
> +	%pB     prev_fn_of_versatile_init+0x88/0x88

I was curious why so many lines were changed here. You converted
the 2nd tab to spaces. I put back the tab. The result is:

--- 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
 
https://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk.git/commit/?h=for-4.16-deprecate-printk-pf&id=78675fe41d57c2bf9cb671f0a85b369a5a156f0a

>  
> diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
> index bd118a6c60cb..1bcfe221e62c 100644
> --- a/include/linux/kallsyms.h
> +++ b/include/linux/kallsyms.h
> +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;
> +}

It is a bit too long for an inline function but I did not find a
better solution. It should always be defined and all suitable
.c files are compiled only under certain configuration. Well,
it is a nop on most architectures.

Best Regards,
Petr
Sergey Senozhatsky Dec. 6, 2017, 10:46 a.m. UTC | #6
On (12/06/17 11:32), Petr Mladek wrote:
[..]
> > diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> > index aa0a776c817a..02745028e909 100644
> > --- a/Documentation/printk-formats.txt
> > +++ b/Documentation/printk-formats.txt
> > @@ -61,41 +61,31 @@ Symbols/Function Pointers
> >  
> >  ::
> >  
> > -	%pF	versatile_init+0x0/0x110
> > -	%pf	versatile_init
> > -	%pS	versatile_init+0x0/0x110
> > -	%pSR	versatile_init+0x9/0x110
> > +	%pS     versatile_init+0x0/0x110
> > +	%ps     versatile_init
> > +	%pF     versatile_init+0x0/0x110
> > +	%pf     versatile_init
> > +	%pSR    versatile_init+0x9/0x110
> >  		(with __builtin_extract_return_addr() translation)
> > -	%ps	versatile_init
> > -	%pB	prev_fn_of_versatile_init+0x88/0x88
> > +	%pB     prev_fn_of_versatile_init+0x88/0x88
> 
> I was curious why so many lines were changed here. You converted
> the 2nd tab to spaces. I put back the tab. The result is:

ew... how did that happen. thanks for fixing up.

> > +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;
> > +}
> 
> It is a bit too long for an inline function but I did not find a
> better solution. It should always be defined and all suitable
> .c files are compiled only under certain configuration. Well,
> it is a nop on most architectures.

or we can move dereference_symbol_descriptor() to vsprintf.c,
since all the functions it depends on are now available either
as exported symbols or via kallsyms header file. not that it
annoys me, so we can keep it as it is.

	-ss
diff mbox series

Patch

diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index 361789df51ec..2f17e684b72e 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -50,42 +50,31 @@  Symbols/Function Pointers
 
 ::
 
-	%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 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.
+        %pS     versatile_init+0x0/0x110
+        %ps     versatile_init
+        %pF     versatile_init+0x0/0x110
+        %pf     versatile_init
+        %pSR    versatile_init+0x9/0x110
+                (with __builtin_extract_return_addr() translation)
+        %pB     prev_fn_of_versatile_init+0x88/0x88
+
+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.
 
-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/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 11dd93e42580..73f7e874c3e1 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -16,6 +16,8 @@ 
 
 struct module;
 
+void *dereference_symbol_descriptor(void *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 1966fe1c2b57..18b3dffc4b84 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -411,6 +411,25 @@  static int __sprint_symbol(char *buffer, unsigned long address,
 	return len;
 }
 
+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;
+}
+
 /**
  * sprint_symbol - Look up a kernel symbol and return it in a text buffer
  * @buffer: buffer to be stored
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 1746bae94d41..16e2eefb0f79 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -40,7 +40,6 @@ 
 #include "../mm/internal.h"	/* For the trace_print_flags arrays */
 
 #include <asm/page.h>		/* for PAGE_SIZE */
-#include <asm/sections.h>	/* for dereference_function_descriptor() */
 #include <asm/byteorder.h>	/* cpu_to_le16 */
 
 #include <linux/string_helpers.h>
@@ -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':