mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-18 17:54:13 +08:00
b865ea6430
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: Sergey 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: Petr Mladek <pmladek@suse.com>
145 lines
5.0 KiB
C
145 lines
5.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_GENERIC_SECTIONS_H_
|
|
#define _ASM_GENERIC_SECTIONS_H_
|
|
|
|
/* References to section boundaries */
|
|
|
|
#include <linux/compiler.h>
|
|
#include <linux/types.h>
|
|
|
|
/*
|
|
* Usage guidelines:
|
|
* _text, _data: architecture specific, don't use them in arch-independent code
|
|
* [_stext, _etext]: contains .text.* sections, may also contain .rodata.*
|
|
* and/or .init.* sections
|
|
* [_sdata, _edata]: contains .data.* sections, may also contain .rodata.*
|
|
* and/or .init.* sections.
|
|
* [__start_rodata, __end_rodata]: contains .rodata.* sections
|
|
* [__start_ro_after_init, __end_ro_after_init]:
|
|
* contains .data..ro_after_init section
|
|
* [__init_begin, __init_end]: contains .init.* sections, but .init.text.*
|
|
* may be out of this range on some architectures.
|
|
* [_sinittext, _einittext]: contains .init.text.* sections
|
|
* [__bss_start, __bss_stop]: contains BSS sections
|
|
*
|
|
* Following global variables are optional and may be unavailable on some
|
|
* architectures and/or kernel configurations.
|
|
* _text, _data
|
|
* __kprobes_text_start, __kprobes_text_end
|
|
* __entry_text_start, __entry_text_end
|
|
* __ctors_start, __ctors_end
|
|
* __irqentry_text_start, __irqentry_text_end
|
|
* __softirqentry_text_start, __softirqentry_text_end
|
|
* __start_opd, __end_opd
|
|
*/
|
|
extern char _text[], _stext[], _etext[];
|
|
extern char _data[], _sdata[], _edata[];
|
|
extern char __bss_start[], __bss_stop[];
|
|
extern char __init_begin[], __init_end[];
|
|
extern char _sinittext[], _einittext[];
|
|
extern char __start_ro_after_init[], __end_ro_after_init[];
|
|
extern char _end[];
|
|
extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[];
|
|
extern char __kprobes_text_start[], __kprobes_text_end[];
|
|
extern char __entry_text_start[], __entry_text_end[];
|
|
extern char __start_rodata[], __end_rodata[];
|
|
extern char __irqentry_text_start[], __irqentry_text_end[];
|
|
extern char __softirqentry_text_start[], __softirqentry_text_end[];
|
|
extern char __start_once[], __end_once[];
|
|
|
|
/* Start and end of .ctors section - used for constructor calls. */
|
|
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;
|
|
|
|
/* Function descriptor handling (if any). Override in asm/sections.h */
|
|
#ifndef dereference_function_descriptor
|
|
#define dereference_function_descriptor(p) (p)
|
|
#define dereference_kernel_function_descriptor(p) (p)
|
|
#endif
|
|
|
|
/* random extra sections (if any). Override
|
|
* in asm/sections.h */
|
|
#ifndef arch_is_kernel_text
|
|
static inline int arch_is_kernel_text(unsigned long addr)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifndef arch_is_kernel_data
|
|
static inline int arch_is_kernel_data(unsigned long addr)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* memory_contains - checks if an object is contained within a memory region
|
|
* @begin: virtual address of the beginning of the memory region
|
|
* @end: virtual address of the end of the memory region
|
|
* @virt: virtual address of the memory object
|
|
* @size: size of the memory object
|
|
*
|
|
* Returns: true if the object specified by @virt and @size is entirely
|
|
* contained within the memory region defined by @begin and @end, false
|
|
* otherwise.
|
|
*/
|
|
static inline bool memory_contains(void *begin, void *end, void *virt,
|
|
size_t size)
|
|
{
|
|
return virt >= begin && virt + size <= end;
|
|
}
|
|
|
|
/**
|
|
* memory_intersects - checks if the region occupied by an object intersects
|
|
* with another memory region
|
|
* @begin: virtual address of the beginning of the memory regien
|
|
* @end: virtual address of the end of the memory region
|
|
* @virt: virtual address of the memory object
|
|
* @size: size of the memory object
|
|
*
|
|
* Returns: true if an object's memory region, specified by @virt and @size,
|
|
* intersects with the region specified by @begin and @end, false otherwise.
|
|
*/
|
|
static inline bool memory_intersects(void *begin, void *end, void *virt,
|
|
size_t size)
|
|
{
|
|
void *vend = virt + size;
|
|
|
|
return (virt >= begin && virt < end) || (vend >= begin && vend < end);
|
|
}
|
|
|
|
/**
|
|
* init_section_contains - checks if an object is contained within the init
|
|
* section
|
|
* @virt: virtual address of the memory object
|
|
* @size: size of the memory object
|
|
*
|
|
* Returns: true if the object specified by @virt and @size is entirely
|
|
* contained within the init section, false otherwise.
|
|
*/
|
|
static inline bool init_section_contains(void *virt, size_t size)
|
|
{
|
|
return memory_contains(__init_begin, __init_end, virt, size);
|
|
}
|
|
|
|
/**
|
|
* init_section_intersects - checks if the region occupied by an object
|
|
* intersects with the init section
|
|
* @virt: virtual address of the memory object
|
|
* @size: size of the memory object
|
|
*
|
|
* Returns: true if an object's memory region, specified by @virt and @size,
|
|
* intersects with the init section, false otherwise.
|
|
*/
|
|
static inline bool init_section_intersects(void *virt, size_t size)
|
|
{
|
|
return memory_intersects(__init_begin, __init_end, virt, size);
|
|
}
|
|
|
|
#endif /* _ASM_GENERIC_SECTIONS_H_ */
|