Commit b865ea64 authored by Sergey Senozhatsky's avatar Sergey Senozhatsky Committed by Petr Mladek

sections: split dereference_function_descriptor()

There are two format specifiers to print out a pointer in symbolic
format: '%pS/%ps' and '%pF/%pf'. On most architectures, the two
mean exactly the same thing, but some architectures (ia64, ppc64,
parisc64) use an indirect pointer for C function pointers, where
the function pointer points to a function descriptor (which in
turn contains the actual pointer to the code). The '%pF/%pf, when
used appropriately, automatically does the appropriate function
descriptor dereference on such architectures.

The "when used appropriately" part is tricky. Basically this is
a subtle ABI detail, specific to some platforms, that made it to
the API level and people can be unaware of it and miss the whole
"we need to dereference the function" business out. [1] proves
that point (note that it fixes only '%pF' and '%pS', there might
be '%pf' and '%ps' cases as well).

It appears that we can handle everything within the affected
arches and make '%pS/%ps' smart enough to retire '%pF/%pf'.
Function descriptors live in .opd elf section and all affected
arches (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.

This patch does the first step, it
a) adds dereference_kernel_function_descriptor() function.
b) adds a weak alias to dereference_module_function_descriptor()
   function.

So, for the time being, we will have:
1) dereference_function_descriptor()
   A generic function, that simply dereferences the pointer. There is
   bunch of places that call it: kgdbts, init/main.c, extable, etc.

2) dereference_kernel_function_descriptor()
   A function to call on kernel symbols that does kernel .opd section
   address range test.

3) dereference_module_function_descriptor()
   A function to call on modules' symbols that does modules' .opd
   section address range test.

[1] https://marc.info/?l=linux-kernel&m=150472969730573

Link: http://lkml.kernel.org/r/20171109234830.5067-2-sergey.senozhatsky@gmail.com
To: Fenghua Yu <fenghua.yu@intel.com>
To: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: Paul Mackerras <paulus@samba.org>
To: Michael Ellerman <mpe@ellerman.id.au>
To: 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: default avatarSergey 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: default avatarPetr Mladek <pmladek@suse.com>
parent ce666d91
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
* __ctors_start, __ctors_end * __ctors_start, __ctors_end
* __irqentry_text_start, __irqentry_text_end * __irqentry_text_start, __irqentry_text_end
* __softirqentry_text_start, __softirqentry_text_end * __softirqentry_text_start, __softirqentry_text_end
* __start_opd, __end_opd
*/ */
extern char _text[], _stext[], _etext[]; extern char _text[], _stext[], _etext[];
extern char _data[], _sdata[], _edata[]; extern char _data[], _sdata[], _edata[];
...@@ -49,12 +50,15 @@ extern char __start_once[], __end_once[]; ...@@ -49,12 +50,15 @@ extern char __start_once[], __end_once[];
/* Start and end of .ctors section - used for constructor calls. */ /* Start and end of .ctors section - used for constructor calls. */
extern char __ctors_start[], __ctors_end[]; 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; extern __visible const void __nosave_begin, __nosave_end;
/* function descriptor handling (if any). Override /* Function descriptor handling (if any). Override in asm/sections.h */
* in asm/sections.h */
#ifndef dereference_function_descriptor #ifndef dereference_function_descriptor
#define dereference_function_descriptor(p) (p) #define dereference_function_descriptor(p) (p)
#define dereference_kernel_function_descriptor(p) (p)
#endif #endif
/* random extra sections (if any). Override /* random extra sections (if any). Override
......
...@@ -606,6 +606,9 @@ int ref_module(struct module *a, struct module *b); ...@@ -606,6 +606,9 @@ int ref_module(struct module *a, struct module *b);
__mod ? __mod->name : "kernel"; \ __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 /* For kallsyms to ask for address resolution. namebuf should be at
* least KSYM_NAME_LEN long: a pointer to namebuf is returned if * least KSYM_NAME_LEN long: a pointer to namebuf is returned if
* found, otherwise NULL. */ * found, otherwise NULL. */
...@@ -760,6 +763,13 @@ static inline bool is_module_sig_enforced(void) ...@@ -760,6 +763,13 @@ static inline bool is_module_sig_enforced(void)
return false; return false;
} }
/* Dereference module function descriptor */
static inline
void *dereference_module_function_descriptor(struct module *mod, void *ptr)
{
return ptr;
}
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
......
...@@ -3938,6 +3938,12 @@ static const char *get_ksymbol(struct module *mod, ...@@ -3938,6 +3938,12 @@ static const char *get_ksymbol(struct module *mod,
return symname(kallsyms, best); 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 /* For kallsyms to ask for address resolution. NULL means not found. Careful
* not to lock to avoid deadlock on oopses, simply disable preemption. */ * not to lock to avoid deadlock on oopses, simply disable preemption. */
const char *module_address_lookup(unsigned long addr, const char *module_address_lookup(unsigned long addr,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment