Skip to content

Commit 04b8eb7

Browse files
sergey-senozhatskypmladek
authored andcommitted
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. Link: http://lkml.kernel.org/r/20171206043649.GB15885@jagdpanzerIV Cc: Fenghua Yu <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: James Bottomley <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Jessica Yu <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Signed-off-by: Sergey Senozhatsky <[email protected]> Tested-by: Tony Luck <[email protected]> #ia64 Tested-by: Santosh Sivaraj <[email protected]> #powerpc Tested-by: Helge Deller <[email protected]> #parisc64 Signed-off-by: Petr Mladek <[email protected]>
1 parent 1705bd6 commit 04b8eb7

File tree

4 files changed

+68
-61
lines changed

4 files changed

+68
-61
lines changed

Documentation/printk-formats.txt

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,42 +50,31 @@ Symbols/Function Pointers
5050

5151
::
5252

53+
%pS versatile_init+0x0/0x110
54+
%ps versatile_init
5355
%pF versatile_init+0x0/0x110
5456
%pf versatile_init
55-
%pS versatile_init+0x0/0x110
5657
%pSR versatile_init+0x9/0x110
5758
(with __builtin_extract_return_addr() translation)
58-
%ps versatile_init
5959
%pB prev_fn_of_versatile_init+0x88/0x88
6060

61-
The ``F`` and ``f`` specifiers are for printing function pointers,
62-
for example, f->func, &gettimeofday. They have the same result as
63-
``S`` and ``s`` specifiers. But they do an extra conversion on
64-
ia64, ppc64 and parisc64 architectures where the function pointers
65-
are actually function descriptors.
61+
The ``S`` and ``s`` specifiers are used for printing a pointer in symbolic
62+
format. They result in the symbol name with (``S``) or without (``s``)
63+
offsets. If KALLSYMS are disabled then the symbol address is printed instead.
6664

67-
The ``S`` and ``s`` specifiers can be used for printing symbols
68-
from direct addresses, for example, __builtin_return_address(0),
69-
(void *)regs->ip. They result in the symbol name with (``S``) or
70-
without (``s``) offsets. If KALLSYMS are disabled then the symbol
71-
address is printed instead.
65+
Note, that the ``F`` and ``f`` specifiers are identical to ``S`` (``s``)
66+
and thus deprecated. We have ``F`` and ``f`` because on ia64, ppc64 and
67+
parisc64 function pointers are indirect and, in fact, are function
68+
descriptors, which require additional dereferencing before we can lookup
69+
the symbol. As of now, ``S`` and ``s`` perform dereferencing on those
70+
platforms (when needed), so ``F`` and ``f`` exist for compatibility
71+
reasons only.
7272

7373
The ``B`` specifier results in the symbol name with offsets and should be
7474
used when printing stack backtraces. The specifier takes into
7575
consideration the effect of compiler optimisations which may occur
7676
when tail-call``s are used and marked with the noreturn GCC attribute.
7777

78-
Examples::
79-
80-
printk("Going to call: %pF\n", gettimeofday);
81-
printk("Going to call: %pF\n", p->func);
82-
printk("%s: called from %pS\n", __func__, (void *)_RET_IP_);
83-
printk("%s: called from %pS\n", __func__,
84-
(void *)__builtin_return_address(0));
85-
printk("Faulted at %pS\n", (void *)regs->ip);
86-
printk(" %s%pB\n", (reliable ? "" : "? "), (void *)*stack);
87-
88-
8978
Kernel Pointers
9079
===============
9180

include/linux/kallsyms.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#include <linux/errno.h>
1010
#include <linux/kernel.h>
1111
#include <linux/stddef.h>
12+
#include <linux/mm.h>
13+
#include <linux/module.h>
14+
15+
#include <asm/sections.h>
1216

1317
#define KSYM_NAME_LEN 128
1418
#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
@@ -22,6 +26,56 @@
2226

2327
struct module;
2428

29+
static inline int is_kernel_inittext(unsigned long addr)
30+
{
31+
if (addr >= (unsigned long)_sinittext
32+
&& addr <= (unsigned long)_einittext)
33+
return 1;
34+
return 0;
35+
}
36+
37+
static inline int is_kernel_text(unsigned long addr)
38+
{
39+
if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) ||
40+
arch_is_kernel_text(addr))
41+
return 1;
42+
return in_gate_area_no_mm(addr);
43+
}
44+
45+
static inline int is_kernel(unsigned long addr)
46+
{
47+
if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)
48+
return 1;
49+
return in_gate_area_no_mm(addr);
50+
}
51+
52+
static inline int is_ksym_addr(unsigned long addr)
53+
{
54+
if (IS_ENABLED(CONFIG_KALLSYMS_ALL))
55+
return is_kernel(addr);
56+
57+
return is_kernel_text(addr) || is_kernel_inittext(addr);
58+
}
59+
60+
static inline void *dereference_symbol_descriptor(void *ptr)
61+
{
62+
#ifdef HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR
63+
struct module *mod;
64+
65+
ptr = dereference_kernel_function_descriptor(ptr);
66+
if (is_ksym_addr((unsigned long)ptr))
67+
return ptr;
68+
69+
preempt_disable();
70+
mod = __module_address((unsigned long)ptr);
71+
preempt_enable();
72+
73+
if (mod)
74+
ptr = dereference_module_function_descriptor(mod, ptr);
75+
#endif
76+
return ptr;
77+
}
78+
2579
#ifdef CONFIG_KALLSYMS
2680
/* Lookup the address for a symbol. Returns 0 if not found. */
2781
unsigned long kallsyms_lookup_name(const char *name);

kernel/kallsyms.c

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,19 @@
1212
* compression (see scripts/kallsyms.c for a more complete description)
1313
*/
1414
#include <linux/kallsyms.h>
15-
#include <linux/module.h>
1615
#include <linux/init.h>
1716
#include <linux/seq_file.h>
1817
#include <linux/fs.h>
1918
#include <linux/kdb.h>
2019
#include <linux/err.h>
2120
#include <linux/proc_fs.h>
2221
#include <linux/sched.h> /* for cond_resched */
23-
#include <linux/mm.h>
2422
#include <linux/ctype.h>
2523
#include <linux/slab.h>
2624
#include <linux/filter.h>
2725
#include <linux/ftrace.h>
2826
#include <linux/compiler.h>
2927

30-
#include <asm/sections.h>
31-
3228
/*
3329
* These will be re-linked against their real values
3430
* during the second link stage.
@@ -52,37 +48,6 @@ extern const u16 kallsyms_token_index[] __weak;
5248

5349
extern const unsigned long kallsyms_markers[] __weak;
5450

55-
static inline int is_kernel_inittext(unsigned long addr)
56-
{
57-
if (addr >= (unsigned long)_sinittext
58-
&& addr <= (unsigned long)_einittext)
59-
return 1;
60-
return 0;
61-
}
62-
63-
static inline int is_kernel_text(unsigned long addr)
64-
{
65-
if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) ||
66-
arch_is_kernel_text(addr))
67-
return 1;
68-
return in_gate_area_no_mm(addr);
69-
}
70-
71-
static inline int is_kernel(unsigned long addr)
72-
{
73-
if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)
74-
return 1;
75-
return in_gate_area_no_mm(addr);
76-
}
77-
78-
static int is_ksym_addr(unsigned long addr)
79-
{
80-
if (IS_ENABLED(CONFIG_KALLSYMS_ALL))
81-
return is_kernel(addr);
82-
83-
return is_kernel_text(addr) || is_kernel_inittext(addr);
84-
}
85-
8651
/*
8752
* Expand a compressed symbol data into the resulting uncompressed string,
8853
* if uncompressed string is too long (>= maxlen), it will be truncated,

lib/vsprintf.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
#include "../mm/internal.h" /* For the trace_print_flags arrays */
4141

4242
#include <asm/page.h> /* for PAGE_SIZE */
43-
#include <asm/sections.h> /* for dereference_function_descriptor() */
4443
#include <asm/byteorder.h> /* cpu_to_le16 */
4544

4645
#include <linux/string_helpers.h>
@@ -1723,10 +1722,10 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
17231722
switch (*fmt) {
17241723
case 'F':
17251724
case 'f':
1726-
ptr = dereference_function_descriptor(ptr);
1727-
/* Fallthrough */
17281725
case 'S':
17291726
case 's':
1727+
ptr = dereference_symbol_descriptor(ptr);
1728+
/* Fallthrough */
17301729
case 'B':
17311730
return symbol_string(buf, end, ptr, spec, fmt);
17321731
case 'R':

0 commit comments

Comments
 (0)