Skip to content

Commit

Permalink
Merge branch 'for-4.16-deprecate-printk-pf' into for-4.16
Browse files Browse the repository at this point in the history
  • Loading branch information
pmladek committed Jan 22, 2018
2 parents 6fd78a1 + 1df7338 commit 3ccdc51
Show file tree
Hide file tree
Showing 22 changed files with 191 additions and 71 deletions.
35 changes: 12 additions & 23 deletions Documentation/printk-formats.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

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
===============

Expand Down
10 changes: 9 additions & 1 deletion arch/ia64/include/asm/sections.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ extern char __start_gate_brl_fsys_bubble_down_patchlist[], __end_gate_brl_fsys_b
extern char __start_unwind[], __end_unwind[];
extern char __start_ivt_text[], __end_ivt_text[];

#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1

#undef dereference_function_descriptor
static inline void *dereference_function_descriptor(void *ptr)
{
Expand All @@ -38,6 +40,12 @@ static inline void *dereference_function_descriptor(void *ptr)
return ptr;
}

#undef dereference_kernel_function_descriptor
static inline void *dereference_kernel_function_descriptor(void *ptr)
{
if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd)
return ptr;
return dereference_function_descriptor(ptr);
}

#endif /* _ASM_IA64_SECTIONS_H */

12 changes: 12 additions & 0 deletions arch/ia64/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

#include <asm/patch.h>
#include <asm/unaligned.h>
#include <asm/sections.h>

#define ARCH_MODULE_DEBUG 0

Expand Down Expand Up @@ -918,3 +919,14 @@ module_arch_cleanup (struct module *mod)
if (mod->arch.core_unw_table)
unw_remove_unwind_table(mod->arch.core_unw_table);
}

void *dereference_module_function_descriptor(struct module *mod, void *ptr)
{
Elf64_Shdr *opd = mod->arch.opd;

if (ptr < (void *)opd->sh_addr ||
ptr >= (void *)(opd->sh_addr + opd->sh_size))
return ptr;

return dereference_function_descriptor(ptr);
}
2 changes: 2 additions & 0 deletions arch/ia64/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ SECTIONS {
RODATA

.opd : AT(ADDR(.opd) - LOAD_OFFSET) {
__start_opd = .;
*(.opd)
__end_opd = .;
}

/*
Expand Down
3 changes: 1 addition & 2 deletions arch/openrisc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/unwinder.h>

extern char _etext, _stext;
#include <asm/sections.h>

int kstack_depth_to_print = 0x180;
int lwa_flag;
Expand Down
2 changes: 2 additions & 0 deletions arch/parisc/boot/compressed/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ SECTIONS
. = ALIGN(16);
/* Linkage tables */
.opd : {
__start_opd = .;
*(.opd)
__end_opd = .;
} PROVIDE (__gp = .);
.plt : {
*(.plt)
Expand Down
6 changes: 6 additions & 0 deletions arch/parisc/include/asm/sections.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@
#include <asm-generic/sections.h>

#ifdef CONFIG_64BIT

#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1

#undef dereference_function_descriptor
void *dereference_function_descriptor(void *);

#undef dereference_kernel_function_descriptor
void *dereference_kernel_function_descriptor(void *);
#endif

#endif
16 changes: 16 additions & 0 deletions arch/parisc/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@

#include <asm/pgtable.h>
#include <asm/unwind.h>
#include <asm/sections.h>

#if 0
#define DEBUGP printk
Expand Down Expand Up @@ -954,3 +955,18 @@ void module_arch_cleanup(struct module *mod)
{
deregister_unwind_table(mod);
}

#ifdef CONFIG_64BIT
void *dereference_module_function_descriptor(struct module *mod, void *ptr)
{
unsigned long start_opd = (Elf64_Addr)mod->core_layout.base +
mod->arch.fdesc_offset;
unsigned long end_opd = start_opd +
mod->arch.fdesc_count * sizeof(Elf64_Fdesc);

if (ptr < (void *)start_opd || ptr >= (void *)end_opd)
return ptr;

return dereference_function_descriptor(ptr);
}
#endif
9 changes: 9 additions & 0 deletions arch/parisc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,15 @@ void *dereference_function_descriptor(void *ptr)
ptr = p;
return ptr;
}

void *dereference_kernel_function_descriptor(void *ptr)
{
if (ptr < (void *)__start_opd ||
ptr >= (void *)__end_opd)
return ptr;

return dereference_function_descriptor(ptr);
}
#endif

static inline unsigned long brk_rnd(void)
Expand Down
2 changes: 2 additions & 0 deletions arch/parisc/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ SECTIONS
. = ALIGN(16);
/* Linkage tables */
.opd : {
__start_opd = .;
*(.opd)
__end_opd = .;
} PROVIDE (__gp = .);
.plt : {
*(.plt)
Expand Down
3 changes: 3 additions & 0 deletions arch/powerpc/include/asm/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ struct mod_arch_specific {
unsigned long tramp;
#endif

/* For module function descriptor dereference */
unsigned long start_opd;
unsigned long end_opd;
#else /* powerpc64 */
/* Indices of PLT sections within module. */
unsigned int core_plt_section;
Expand Down
12 changes: 12 additions & 0 deletions arch/powerpc/include/asm/sections.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ static inline int overlaps_kvm_tmp(unsigned long start, unsigned long end)
}

#ifdef PPC64_ELF_ABI_v1

#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1

#undef dereference_function_descriptor
static inline void *dereference_function_descriptor(void *ptr)
{
Expand All @@ -76,6 +79,15 @@ static inline void *dereference_function_descriptor(void *ptr)
ptr = p;
return ptr;
}

#undef dereference_kernel_function_descriptor
static inline void *dereference_kernel_function_descriptor(void *ptr)
{
if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd)
return ptr;

return dereference_function_descriptor(ptr);
}
#endif /* PPC64_ELF_ABI_v1 */

#endif
Expand Down
14 changes: 14 additions & 0 deletions arch/powerpc/kernel/module_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ static unsigned int local_entry_offset(const Elf64_Sym *sym)
{
return 0;
}

void *dereference_module_function_descriptor(struct module *mod, void *ptr)
{
if (ptr < (void *)mod->arch.start_opd ||
ptr >= (void *)mod->arch.end_opd)
return ptr;

return dereference_function_descriptor(ptr);
}
#endif

#define STUB_MAGIC 0x73747562 /* stub */
Expand Down Expand Up @@ -344,6 +353,11 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0)
dedotify_versions((void *)hdr + sechdrs[i].sh_offset,
sechdrs[i].sh_size);
else if (!strcmp(secstrings + sechdrs[i].sh_name, ".opd")) {
me->arch.start_opd = sechdrs[i].sh_addr;
me->arch.end_opd = sechdrs[i].sh_addr +
sechdrs[i].sh_size;
}

/* We don't handle .init for the moment: rename to _init */
while ((p = strstr(secstrings + sechdrs[i].sh_name, ".init")))
Expand Down
2 changes: 2 additions & 0 deletions arch/powerpc/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,9 @@ SECTIONS
}

.opd : AT(ADDR(.opd) - LOAD_OFFSET) {
__start_opd = .;
*(.opd)
__end_opd = .;
}

. = ALIGN(256);
Expand Down
8 changes: 6 additions & 2 deletions include/asm-generic/sections.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
* __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[];
Expand All @@ -49,12 +50,15 @@ 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 */
/* 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
Expand Down
54 changes: 54 additions & 0 deletions include/linux/kallsyms.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/mm.h>
#include <linux/module.h>

#include <asm/sections.h>

#define KSYM_NAME_LEN 128
#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
Expand All @@ -22,6 +26,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);
Expand Down
10 changes: 10 additions & 0 deletions include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,9 @@ int ref_module(struct module *a, struct module *b);
__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
* least KSYM_NAME_LEN long: a pointer to namebuf is returned if
* found, otherwise NULL. */
Expand Down Expand Up @@ -760,6 +763,13 @@ static inline bool is_module_sig_enforced(void)
return false;
}

/* Dereference module function descriptor */
static inline
void *dereference_module_function_descriptor(struct module *mod, void *ptr)
{
return ptr;
}

#endif /* CONFIG_MODULES */

#ifdef CONFIG_SYSFS
Expand Down
Loading

0 comments on commit 3ccdc51

Please sign in to comment.