提交 04b8eb7a 编写于 作者: S Sergey Senozhatsky 提交者: Petr Mladek

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 <fenghua.yu@intel.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: James Bottomley <jejb@parisc-linux.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jessica Yu <jeyu@kernel.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-ia64@vger.kernel.org
Cc: linux-parisc@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: NSergey Senozhatsky <sergey.senozhatsky@gmail.com>
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
Signed-off-by: NPetr Mladek <pmladek@suse.com>
上级 1705bd6a
...@@ -50,42 +50,31 @@ Symbols/Function Pointers ...@@ -50,42 +50,31 @@ Symbols/Function Pointers
:: ::
%pS versatile_init+0x0/0x110
%ps versatile_init
%pF versatile_init+0x0/0x110 %pF versatile_init+0x0/0x110
%pf versatile_init %pf versatile_init
%pS versatile_init+0x0/0x110
%pSR versatile_init+0x9/0x110 %pSR versatile_init+0x9/0x110
(with __builtin_extract_return_addr() translation) (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, The ``S`` and ``s`` specifiers are used for printing a pointer in symbolic
for example, f->func, &gettimeofday. They have the same result as format. They result in the symbol name with (``S``) or without (``s``)
``S`` and ``s`` specifiers. But they do an extra conversion on offsets. If KALLSYMS are disabled then the symbol address is printed instead.
ia64, ppc64 and parisc64 architectures where the function pointers
are actually function descriptors.
The ``S`` and ``s`` specifiers can be used for printing symbols Note, that the ``F`` and ``f`` specifiers are identical to ``S`` (``s``)
from direct addresses, for example, __builtin_return_address(0), and thus deprecated. We have ``F`` and ``f`` because on ia64, ppc64 and
(void *)regs->ip. They result in the symbol name with (``S``) or parisc64 function pointers are indirect and, in fact, are function
without (``s``) offsets. If KALLSYMS are disabled then the symbol descriptors, which require additional dereferencing before we can lookup
address is printed instead. 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 The ``B`` specifier results in the symbol name with offsets and should be
used when printing stack backtraces. The specifier takes into used when printing stack backtraces. The specifier takes into
consideration the effect of compiler optimisations which may occur consideration the effect of compiler optimisations which may occur
when tail-call``s are used and marked with the noreturn GCC attribute. 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 Kernel Pointers
=============== ===============
......
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <asm/sections.h>
#define KSYM_NAME_LEN 128 #define KSYM_NAME_LEN 128
#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \ #define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
...@@ -22,6 +26,56 @@ ...@@ -22,6 +26,56 @@
struct module; 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 #ifdef CONFIG_KALLSYMS
/* Lookup the address for a symbol. Returns 0 if not found. */ /* Lookup the address for a symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name); unsigned long kallsyms_lookup_name(const char *name);
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
* compression (see scripts/kallsyms.c for a more complete description) * compression (see scripts/kallsyms.c for a more complete description)
*/ */
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -20,15 +19,12 @@ ...@@ -20,15 +19,12 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/sched.h> /* for cond_resched */ #include <linux/sched.h> /* for cond_resched */
#include <linux/mm.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <asm/sections.h>
/* /*
* These will be re-linked against their real values * These will be re-linked against their real values
* during the second link stage. * during the second link stage.
...@@ -52,37 +48,6 @@ extern const u16 kallsyms_token_index[] __weak; ...@@ -52,37 +48,6 @@ extern const u16 kallsyms_token_index[] __weak;
extern const unsigned long kallsyms_markers[] __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, * Expand a compressed symbol data into the resulting uncompressed string,
* if uncompressed string is too long (>= maxlen), it will be truncated, * if uncompressed string is too long (>= maxlen), it will be truncated,
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include "../mm/internal.h" /* For the trace_print_flags arrays */ #include "../mm/internal.h" /* For the trace_print_flags arrays */
#include <asm/page.h> /* for PAGE_SIZE */ #include <asm/page.h> /* for PAGE_SIZE */
#include <asm/sections.h> /* for dereference_function_descriptor() */
#include <asm/byteorder.h> /* cpu_to_le16 */ #include <asm/byteorder.h> /* cpu_to_le16 */
#include <linux/string_helpers.h> #include <linux/string_helpers.h>
...@@ -1723,10 +1722,10 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, ...@@ -1723,10 +1722,10 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
switch (*fmt) { switch (*fmt) {
case 'F': case 'F':
case 'f': case 'f':
ptr = dereference_function_descriptor(ptr);
/* Fallthrough */
case 'S': case 'S':
case 's': case 's':
ptr = dereference_symbol_descriptor(ptr);
/* Fallthrough */
case 'B': case 'B':
return symbol_string(buf, end, ptr, spec, fmt); return symbol_string(buf, end, ptr, spec, fmt);
case 'R': case 'R':
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册